【问题标题】:How do I properly create a custom action in Rails?如何在 Rails 中正确创建自定义操作?
【发布时间】:2013-02-22 18:17:34
【问题描述】:

我正在尝试创建自定义表单,允许管理员打开和关闭用户的用户权限,并将它们保存到数据库中。我一定是做错了什么,因为页面生成正常,提交按钮提交给操作正常,但没有任何东西保存到数据库中,它只是再次呈现我的初始视图。谁能看到我做错了什么?

代码

路线:

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 %>

【问题讨论】:

  • 当你说“它只是再次渲染我的初始视图”时,你的意思是它渲染了分配视图吗?
  • 它显示了分配视图的内容,是的,我假设这是render 'assign' 的结果,因为它不保存。 url 更改为 assign_update,如果我取消选中该框,它将保持未选中状态,但是通过控制台检查数据库时,admin 属性未更改。
  • 它确实将它从 params 哈希中删除,但它也将它分配给变量admin_protected,之后无论如何它都没有用了。当我尝试以稍微不同的方式进行操作时,这有点剩余。即使我改变它也不起作用。无论哪种方式,变量仍然被赋予相同的值。
  • 您是否对用户模型有任何验证?我认为对其他用户属性的验证可能会阻止用户实例被更新。要检查这一点,请使用save! 而不是save
  • 哦等等,我想你可能想试试update_attribute 方法。 It seems to skip model validation and mass assignment protection which is exactly what you need.

标签: ruby-on-rails ruby-on-rails-3 rails-activerecord


【解决方案1】:

所以总结一下我们在问题下方评论部分的对话......

发现问题是对其他用户模型属性的验证。无法保存用户实例,因为在执行 save 方法时未通过验证。因此,Rails 只是呈现分配视图。

update_attribute 方法在没有模型验证和批量分配保护的情况下更新属性。在这种情况下,admin 属性符合这两个标准。

【讨论】:

    【解决方案2】:

    您应该在模型中使用 attr_accessible 并从参数中手动选择这些字段并单独分配它们,确保 admin 字段不包含在分配给 attr_accessible 声明的字段列表中

    所以

    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 %>
    

    它应该让您、广告您的用户更清楚地了解问题所在以及如何解决问题

    【讨论】:

    • 这是一个有趣的观察。如果问题在于管理属性的批量分配,Rails 不应该抛出批量分配异常而不是重新渲染分配视图吗?
    • 我在我的模型中使用attr_accessible,并且管理员不在列表中。此外,据我所知,您对代码的更改并没有真正改变它的功能。您仍在手动设置变量,而不是使用 update_attributes 这正是我的代码所做的。您所做的只是将我分配给@user.admin 的值移出变量admin_protected
    • 我应该补充一点,就像我尝试过的健全性检查一样,它的功能相同。 :)
    • 添加一些 logger.debug 语句来看看发生了什么。
    • 另外在渲染视图中你看到了什么错误?我假设您正在遍历错误列表并显示它们?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多