问题
I am using Ruby on Rails (3.2.2), globalize3 (0.2.0) and batch_translations (0.1.2) ruby-gems. I would like to solve the following problem generated when using the batch_translations ruby-gem:
ActiveModel::MassAssignmentSecurity::Error in Admin::ArticlesController#update
Can't mass-assign protected attributes: translations_attributes
In my ROOT_RAILS/Gemfile file I have:
...
gem 'globalize3'
gem 'batch_translations'
In my ROOT_RAILS/app/models/admin/article.rb file I have:
class Admin::Article < ActiveRecord::Base
translates :title
# This is needed to make the batch_translations to work.
accepts_nested_attributes_for :translations
...
end
In my ROOT_RAILS/app/views/admin/articles/_form.html.erb file I have:
<%= 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 %>
In my ROOT_RAILS/app/controllers/admin/articles_controller.html.erb file I have:
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
When I show the edit form all works, but when I submit that form I get the error mentioned above. How can I solve the above error?
UPDATE
I found the solution by using the following code in the ROOT_RAILS/app/models/admin/article.rb file:
class Admin::Article < ActiveRecord::Base
translates :title
attr_accessible :translations_attributes
accepts_nested_attributes_for :translations
...
end
... but making the :translations_attributes accessible is it sure?
回答1:
This will be an issue with the newest version of rails since they patched it. You can change it in the config. See http://weblog.rubyonrails.org/2012/3/30/ann-rails-3-2-3-has-been-released/ for details.
I can confirm that your attr_accessible solution is correct.
回答2:
I had the same problem. I think this is a good solution:
In my Gemfile file I have:
gem 'globalize3', '~> 0.2.0'
gem 'batch_translations', '~> 0.1.2'
In my application.rb file I have:
config.i18n.available_locales = [:es, :en]
In my model (category.rb) I have:
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
In my helper (application_helper.rb) I have:
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
In my translation files I have:
en.yml
en:
locale_selector:
es: 'Spanish'
en: 'English'
es.yml
en:
locale_selector:
es: 'Español'
en: 'Inglés'
In my view file (_form.html.erb) I have:
<%= 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 %>
As you can see, the problem is that rails 3.2 needs to know which attributes can be accesibles, but globalize do not specify this. So I define this with attr_accessible in my model (Category), but I need to add this for translations too, for this reason I add a few lines in the same file to set name accessible for each translation in this model (Category::Translation.class_eval).
回答3:
Yes. Rails is probably configured to only allow mass assignment of attributes that were explicitly allowed.
# This is mass assignment
Model.find(params[id]).update_attributes params[:model]
The whitelist approach is enforced for security. params[:model] can contain anything, even attributes that were not available in the form. An attacker can leverage this and send admin: true along with the other values.
Without attr_accessible, the attacker would have been granted admin rights. However, if :admin had not been on the whitelist, update_attributes would not have updated that specific attribute.
The gems are probably mass assigning under the hood. Make sure you allow them to write to their own attributes.
来源:https://stackoverflow.com/questions/10139245/how-to-solve-the-cant-mass-assign-protected-attributes-translations-attribute