我正在尝试使用simple_form编辑/更新模型记录,但表单不会直接更改模型字段。相反,我提供了几个check_box_tag字段,用于告知更新需要更改的字段。因此,更新未收到可用于更新属性的params [:device]哈希。我正在尝试创建此哈希,但是当我发出@ device.update_attributes(params [:device])时,我得到了ForbiddenAttributesError。
我相信我的强参数列表是正确的。如果我允许在编辑视图中处理一个模型字段(名称),我会收到预期的参数[:device]哈希,一切正常。如果我禁用该字段,因为我不希望它被更改,那么我需要自己创建该哈希并收到错误。当我查看我创建的哈希时,它看起来等同于视图传递的哈希。我不明白为什么会失败。
环境是Ruby 2.0.0,Windows 8.1上的Rails 4.1和RubyMine 6.3。
表格是:< ...一旦工作需要正确的格式...>
<%= simple_form_for @device do |f| %>
<legend><%= controller.action_name.capitalize %> Device:</legend>
<%= f.input :name, disabled: true %>
<%= check_box_tag(:is_admin, 0, @device.admin?) %>
<%= label_tag(:is_admin, "Make admin?") %>
<%= check_box_tag(:chg_pwd) %>
<%= label_tag(:chg_pwd, "Change password?") %>
<%= f.button :submit %>
<% end %>
我发送f.input时收到的params [:device]:name,disabled:false并允许视图生成params [:device]:
ActionController::Parameters (3 element(s))
"{"name"=>"D105", "password"=>"D105Dvgr", "password_confirmation"=>"D105Dvgr"}"
而且,一切正常。
我创建的params [:device]是:
ActionController::Parameters (3 element(s))
"{"name"=>"D106", "password"=>"D106VdAd", "password_confirmation"=>"D106VdAd"}"
并且,我收到禁用属性错误,即使我看到两者没有区别。
更新是:&lt; ...代码需要重构,一旦工作......&gt;
class DevicesController < ApplicationController
before_filter :authenticate_device!
... other methods removed here ...
def edit
@device = Device.find(params[:id])
# my_page = render_to_string controller: 'devices', action: 'edit', layout: "application"
end
def update
authorize! :update, @device, :message => 'Not authorized as an administrator.'
@device = Device.find(params[:id])
pwd_msg = ""
if params[:chg_pwd]
pwd_gen = @device.device + SecureRandom.urlsafe_base64(15).tr('lIO0=_\-', 'sxyzEUM').first(4)
params[:device] = {name: @device.name} if params[:device].nil?
params[:device][:password] = pwd_gen
params[:device][:password_confirmation] = pwd_gen
pwd_msg = ", new password is #{pwd_gen}"
end
if @device.update_attributes(params[:device])
params[:is_admin] ? @device.add_role(:admin) : @device.remove_role(:admin)
flash[:notice] = ["Device updated" + pwd_msg]
redirect_to devices_path
else
@device.errors.messages.each do |key, value|
flash[:alert] = ["Unable to update device"]
@device.errors.messages.each do |key, value|
flash[:alert] << key.to_s.capitalize + " " + value[0]
end
end
redirect_to devices_path
end
end
private
def device_params
params.require(:device).permit(:device, :name, :email, :password, :password_confirmation, :encrypted_password, :salt, :role_ids, :is_admin, :chg_pwd) # TODO minimize when update is working
end
end
模型是:
class Device < ActiveRecord::Base
rolify
devise :database_authenticatable, :rememberable, :trackable, :validatable
validates :device,
presence: true,
length: {minimum: 4 },
uniqueness: {case_sensitive: false }
validates :name,
presence: true
def remember_me
true unless self.admin?
end
def admin
self.add_role :admin
end
def not_admin
self.remove_role :admin
end
def admin?
self.has_role? :admin
end
def device?
self.has_role? :device
end
def vip?
self.has_role? :vip
end
def login=(login)
@login = login
end
def login
@login || self.device || self.email
end
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login) # Note one equal sign. Strange but true.
where(conditions).where(["lower(device) = :value OR lower(email) = :value", { :value => login.downcase }]).first
else
where(conditions).first
end
end
end
新信息:我忽略了在ApplicationController中提供的信息。 Anton Trapp的这个修复程序处理了尚未完全兼容Rails 4的宝石的强大参数:
before_filter do
resource = controller_name.singularize.to_sym
method = "#{resource}_params"
params[resource] &&= send(method) if respond_to?(method, true)
end
我发现使用建议的解决方案:
@device.update_attributes(device_params)
如果更新模型字段,则不起作用。结果是&#34; param not found:device&#34;。如果没有更新模型字段,它确实有效。所以,整个问题都引出了真正错误的问题。
答案 0 :(得分:3)
在DevicesController#update
操作中,更改
@device.update_attributes(params[:device])
要
@device.update_attributes(device_params)
在使用Rails 4.1
时,您需要将要在数据库中插入/更新的属性列入白名单。当您将属性直接传递给update_attributes
方法而不允许它们时,您已收到ActiveModel::ForbiddenAttributesError
<强>更新强>
要解决param not found: device
:
def device_params
if params[:device]
params.require(:device).permit(:device, :name, :email, :password, :password_confirmation, :encrypted_password, :salt, :role_ids, :is_admin, :chg_pwd) # TODO minimize when update is working
end
end
答案 1 :(得分:1)
修复是将字段作为attr_accessor添加到模型中,而不是数据库中,以便可以在表单中正确使用它。
attr_accessor :is_admin, :chg_pwd
然后将视图修改为:
<%= simple_form_for @device do |f| %>
<legend><%= controller.action_name.capitalize %> Device:</legend>
<%= f.input :name, disabled: true %>
<%= f.input :is_admin, as: :boolean, checked_value: true, unchecked_value: false %>
<%= f.input :chg_pwd, as: :boolean, checked_value: true, unchecked_value: false %>
<%= f.button :submit %>
<% end %>
然后,由于Anton Trapp的应用程序控制器代码:
before_filter do
resource = controller_name.singularize.to_sym
method = "#{resource}_params"
params[resource] &&= send(method) if respond_to?(method, true)
end
我可以按如下方式更新设备控制器中的字段:
@device.update_attributes(params[:device])