我正在使用Ruby on Rails(3.2.2),globalize3(0.2.0)和batch_translations(0.1.2)ruby-gems。我想解决使用batch_translations ruby-gem时生成的以下问题:
ActiveModel::MassAssignmentSecurity::Error in Admin::ArticlesController#update
Can't mass-assign protected attributes: translations_attributes
在我的ROOT_RAILS/Gemfile
文件中,我有:
...
gem 'globalize3'
gem 'batch_translations'
在我的ROOT_RAILS/app/models/admin/article.rb
文件中,我有:
class Admin::Article < ActiveRecord::Base
translates :title
# This is needed to make the batch_translations to work.
accepts_nested_attributes_for :translations
...
end
在我的ROOT_RAILS/app/views/admin/articles/_form.html.erb
文件中,我有:
<%= form_for(@admin_article, :url => admin_article_path) do |f| %>
<%= f.label :title %><br />
English translation:
<%= f.text_field :title %>
Italiano translation:
<%
# Note: I am using the '<%= f...' instad of '<% f...' otherwise
# batch_translations doesn't output the input field in the
# front-end content.
%>
<%= f.globalize_fields_for :it do |g| %>
<%= g.text_field :title %>
<% end %>
<% end %>
在我的ROOT_RAILS/app/controllers/admin/articles_controller.html.erb
文件中,我有:
class Admin::ArticlesController < ApplicationController
def update
@admin_article = Article.find(params[:id])
respond_to do |format|
if @admin_article.update_attributes(params[:article])
format.html { redirect_to admin_article_path(@admin_erticle), notice: 'Article was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @admin_article.errors, status: :unprocessable_entity }
end
end
end
...
end
当我显示编辑表单时,所有工作都有效,但当我提交该表单时,我会收到上述错误。 如何解决上述错误?
更新
我使用ROOT_RAILS/app/models/admin/article.rb
文件中的以下代码找到了解决方案:
class Admin::Article < ActiveRecord::Base
translates :title
attr_accessible :translations_attributes
accepts_nested_attributes_for :translations
...
end
...但确保:translations_attributes
可访问?
答案 0 :(得分:4)
我遇到了同样的问题。我认为这是一个很好的解决方案:
在我的Gemfile文件中,我有:
gem 'globalize3', '~> 0.2.0'
gem 'batch_translations', '~> 0.1.2'
在我的application.rb文件中,我有:
config.i18n.available_locales = [:es, :en]
在我的模型(category.rb)中,我有:
class Category < ActiveRecord::Base
attr_accessible :name, :translations_attributes
translates :name
accepts_nested_attributes_for :translations, :reject_if => proc { |attributes| attributes['name'].blank? }
validates :name, :presence => true
end
Category::Translation.class_eval do
attr_accessible :name
end
在我的助手(application_helper.rb)中,我有:
module ApplicationHelper
def find_available_locales
locales = {}
I18n.available_locales.each { |locale| locales[locale] = t("locale_selector.#{locale}") }
locales
end
def available_locales
@available_locales ||= find_available_locales
end
end
在我的翻译文件中,我有:
en.yml
en:
locale_selector:
es: 'Spanish'
en: 'English'
es.yml
en:
locale_selector:
es: 'Español'
en: 'Inglés'
在我的视图文件(_form.html.erb)中,我有:
<%= form_for @category, html: { class: 'form-horizontal' } do |f| %>
<% available_locales.each_pair do |locale, name_locale| -%>
<% if locale == I18n.locale -%>
<div class="control-group">
<%= f.label :name, class: 'control-label' %>
<div class="controls">
<%= f.text_field :name, class: 'text_field' %> <i>(<%= name_locale %>)</i>
</div>
</div>
<% else -%>
<%= f.globalize_fields_for locale do |g| -%>
<div class="control-group">
<%= g.label :name, class: 'control-label' %>
<div class="controls">
<%= g.text_field :name, class: 'text_field' %> <i>(<%= name_locale %>)</i>
</div>
</div>
<% end -%>
<% end -%>
<% end -%>
<div class="form-actions">
<%= f.submit nil, class: 'btn btn-primary' %>
<%= link_to t('.cancel', default: t("helpers.links.cancel")),
categories_path, class: 'btn' %>
</div>
<% end %>
正如您所看到的,问题是rails 3.2需要知道哪些属性可以访问,但globalize不指定此属性。所以我在我的模型(类别)中用attr_accessible定义了这个,但我也需要为翻译添加这个,因此我在同一个文件中添加几行来设置这个模型中每个翻译的可访问名称(Category :: Translation) .class_eval)。
答案 1 :(得分:3)
这将是最新版本的rails的一个问题,因为他们修补了它。您可以在配置中更改它。有关详细信息,请参阅http://weblog.rubyonrails.org/2012/3/30/ann-rails-3-2-3-has-been-released/。
我可以确认您的attr_accessible解决方案是正确的。
答案 2 :(得分:0)
是。 Rails可能配置为仅允许批量分配明确允许的属性。
# This is mass assignment
Model.find(params[id]).update_attributes params[:model]
为了安全起见,强制执行白名单方法。 params[:model]
可以包含任何内容,甚至包含表单中未提供的属性。攻击者可以利用此功能并将admin: true
与其他值一起发送。
如果没有attr_accessible
,攻击者就会被授予管理员权限。但是,如果白名单中未显示:admin
,则update_attributes
将不会更新该特定属性。
宝石可能是引人注目的大规模分配。确保允许他们写入自己的属性。