Как мне правильно создать настраиваемое действие в Rails?

Я пытаюсь создать настраиваемую форму, которая позволяет администраторам включать и отключать пользовательские привилегии пользователей и сохранять их в базе данных. Я, должно быть, делаю что-то совершенно неправильно, потому что страницы генерируются нормально, а кнопка отправки подчиняется действию нормально, но ничего не сохраняется в базе данных, и он просто снова отображает мое первоначальное представление. Кто-нибудь может увидеть, что я делаю не так?

Код

Маршруты:

resources :users do
  member do
    get 'assign'
    put 'assign_update'
  end
end
...

Контроллер (Этот странный способ сделать это - попытка обойти тот факт, что администратор и другие атрибуты недоступны. Это может быть беспорядок.):

...
def assign
  @user = User.find(params[:id])
end

def assign_update
  admin_protected = params[:user].delete(:admin)

  @user = User.find(params[:id])
  @user.admin = admin_protected

  if @user.save
    flash[:success] = "User updated"
    redirect_to users_path
  else
    render 'assign'
  end
end

Вид:

...
<%= form_for(@user, url: { controller: 'users', 
  action: 'assign_update'}, method: 'put') do |f| %>
  <%= f.label :admin, 'Is admin?', class: 'checkbox inline' %>
  <%= f.check_box :admin %>
  <%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>

person Glynne McReynolds    schedule 22.02.2013    source источник
comment
Когда вы говорите, что он просто снова отображает мое первоначальное представление, вы имеете в виду, что он отображает назначенное представление?   -  person Jason Kim    schedule 22.02.2013
comment
Он показывает содержимое представления "Да", которое, как я предполагаю, является результатом render 'assign', потому что оно не сохраняется. URL-адрес изменится на assign_update, и если я сниму флажок, он останется непроверенным, но при проверке базы данных через консоль атрибут администратора не изменится.   -  person Glynne McReynolds    schedule 22.02.2013
comment
Ok. Возможно, это не имеет прямого отношения к проблеме, но admin_protected = params[:user].delete(:admin) кажется подозрительным. Разве эта строка не всегда удаляет атрибут admin из пользовательского параметра?   -  person Jason Kim    schedule 22.02.2013
comment
Он удаляет его из хэша params, но также назначает его переменной admin_protected, после чего он все равно бесполезен. Это немного пережиток того времени, когда я пытался сделать это немного по-другому. Это не работает, даже если я его поменяю. В любом случае переменной по-прежнему присваивается то же значение.   -  person Glynne McReynolds    schedule 22.02.2013
comment
Есть ли у вас случайно какие-либо проверки модели User? Я думаю, что проверки других атрибутов пользователя могут препятствовать обновлению экземпляра пользователя. Чтобы проверить это, нужно использовать save! вместо save.   -  person Jason Kim    schedule 22.02.2013
comment
Ах, теперь это имеет для меня смысл. Я проверяю наличие нескольких атрибутов пользователя в модели. При использовании save! Я получаю исключение из-за отсутствия пароля. Есть мысли о том, как я могу это обойти? Придется ли мне отправлять остальные атрибуты пользователей в форме в скрытых полях или что-то в этом роде?   -  person Glynne McReynolds    schedule 22.02.2013
comment
Не могу сейчас придумать какое-либо немедленное решение. Я думаю, что использование скрытого поля могло бы сработать для других моделей, но не для пользователя из-за поля пароля, предполагая, что вы не можете знать пароль пользователя.   -  person Jason Kim    schedule 22.02.2013
comment
Да, думаю, ты прав. Что ж, в любом случае спасибо за обнаружение проблемы. :)   -  person Glynne McReynolds    schedule 22.02.2013
comment
Ой, подождите, я думаю, вы можете попробовать update_attribute метод. Кажется, что проверка модели пропускается и защита массового размещения - это именно то, что вам нужно.   -  person Jason Kim    schedule 22.02.2013
comment
Это сделало это. Понадобилось время, чтобы разобраться с синтаксисом и все в порядке, но я понял. update_attribute делает свое дело! Спасибо! Также, если вы хотите отправить это в качестве ответа, я приму.   -  person Glynne McReynolds    schedule 22.02.2013


Ответы (2)


Итак, чтобы подвести итог разговора, который у нас был в разделе комментариев под вопросом ...

Обнаружена проблема с проверками других атрибутов пользовательской модели. Экземпляр пользователя не удалось сохранить, поскольку при выполнении метода save не проходили проверки. В результате Rails просто рендерил назначенное представление.

update_attribute метод обновляет атрибут без проверки модели или защиты от массового назначения. И атрибут admin в данном случае соответствует этим двум критериям.

person Jason Kim    schedule 22.02.2013

Вы должны использовать attr_accessible в своей модели и вручную выбирать эти поля из параметров и назначать их индивидуально, убедившись, что поле администратора НЕ включено в список полей, назначенных объявлению attr_accessible.

So

def assign_update
  admin_protected = params[:user].delete(:admin)

  @user = User.find(params[:id])
  @user.admin = admin_protected

  if @user.save
    flash[:success] = "User updated"
    redirect_to users_path
  else
    render 'assign'
  end
end

становится

    def assign_update
#      admin_protected = params[:user].delete(:admin)

      @user = User.find(params[:id])
      @user.admin = params[:user][:admin]

      if @user.save
        flash[:success] = "User updated"
        redirect_to users_path
      else
        render 'assign'
      end
    end

Проблема в том, что в вашем подходе вы все еще выполняете массовые задания.

Чтобы отладить то, что на самом деле происходит, вы должны внимательно посмотреть на вывод файла журнала.

ОБНОВЛЕНИЕ

Проверьте список ошибок. Добавьте в свою форму следующее

  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %> prohibited this account from being saved:</h2>

      <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

Это должно дать вам, вашим пользователям более четкое представление о том, что не так и как это исправить.

person jamesc    schedule 22.02.2013
comment
Это интересное наблюдение. Если проблема связана с массовым назначением атрибута admin, не следует ли Rails генерировать исключение массового назначения вместо повторного рендеринга представления назначения? - person Jason Kim; 22.02.2013
comment
Я использую attr_accessible в своей модели, а администратора нет в списке. Кроме того, ваше изменение кода на самом деле не сильно меняет его функционально, насколько я могу видеть. Вы по-прежнему устанавливаете переменную вручную, а не используете update_attributes, что и делает мой код. Все, что вы сделали, это переместили значение, которое я присвоил @user.admin из переменной admin_protected. - person Glynne McReynolds; 22.02.2013
comment
Я должен добавить, что просто в качестве проверки работоспособности я попробовал его, и он работает так же. :) - person Glynne McReynolds; 22.02.2013
comment
добавьте несколько операторов logger.debug, чтобы увидеть, что происходит. - person jamesc; 23.02.2013
comment
Какие ошибки вы видите в визуализированном виде? Я предполагаю, что вы просматриваете список ошибок и отображаете их? - person jamesc; 23.02.2013
comment
@GlynneMcReynolds Я обновил свой ответ в надежде, что он поможет вам отследить проблему - person jamesc; 23.02.2013