问题
I am creating an app to allow users to record workouts and exercises, with the exercises as a nested model within my workouts form.
routes.rb:
resources :users do
resources :workouts
end
workouts.rb:
attr_accessible :name, :exercises_attributes
has_many :exercises
belongs_to :user
accepts_nested_attributes_for :exercises, :allow_destroy => true
exercise.rb:
attr_accessible :name, :weight, :reps
belongs_to :workout
In my workouts_controller.rb:
def create
@workout = @user.workouts.new(workout_params)
@exercise = @workout.exercises.new(params[:workout][:exercise])
respond_to do |format|
if @workout.save && @exercise.save
//...etc
In my workouts/_form.html.erb:
<%= form_for [@user, @workout], builder: LabeledFormBuilder do |f| %>
<%= f.text_field :name %>
<%= f.fields_for :exercises do |builder| %>
<%= builder.text_field :name %>
<%= builder.text_field :weight %>
<%= builder.text_field :reps %>
<% end %>
<%= f.submit %>
<% end %>
I am having trouble getting fields_for to work as stipulated in the documentation ( http://edgeapi.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for).
It says that you should be able to pass to fields_for the pluralized version of your model if it is in a one-to-many association. This works fine in my workouts#new action, but in my workouts#edit, I have to pass in the singularized version (:exercise) in order to display the current attribute values of the object(the workout). The docs say:
Often this can be simplified by passing just the name of the model object to fields_for - …in which case, if :permission also happens to be the name of an instance variable @permission, the initial state of the input field will reflect the value of that variable’s attribute @permission.admin.
passing :exercises to fields_for does not save the attributes to the database, whereas passing :exercise to fields_for does save it to the database, but doesn't display the current attribute values in the edit action.
In workouts#new and #edit: with fields_for :exercise
<div class="field"><input id="workout_exercise_name" name="workout[exercise][name]" placeholder="name" type="text" /></div>
with fields_for :exercises
<div class="field"><input id="workout_exercises_attributes_0_name" name="workout[exercises_attributes][0][name]" placeholder="name" type="text" /></div>
Finally I have the following in my dev log on workout#create:
Started POST "/users/5/workouts" for 127.0.0.1 at 2013-04-07 14:13:45 -0400
Processing by WorkoutsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"a98ozlUWDtZc49v/PfFds/V0S56R2Y73HsxW6+wjYWI=", "workout"=>{"name"=>"test", "exercise"=>{"name"=>"lunge", "weight"=>"30", "reps"=>"20", "_destroy"=>""}}, "commit"=>"Create Workout", "user_id"=>"5"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", "5"]]
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."auth_token" = 'dHhQQSEecDOetjh-ZROpmw' LIMIT 1
Unpermitted parameters: exercise
WARNING: Can't mass-assign protected attributes for Exercise: _destroy
app/controllers/workouts_controller.rb:32:in `create'
(0.2ms) BEGIN
SQL (0.8ms) INSERT INTO "workouts" ("created_at", "name", "updated_at", "user_id") VALUES ($1, $2, $3, $4) RETURNING "id" [["created_at", Sun, 07 Apr 2013 18:13:45 UTC +00:00], ["name", "test"], ["updated_at", Sun, 07 Apr 2013 18:13:45 UTC +00:00], ["user_id", 5]]
SQL (0.6ms) INSERT INTO "exercises" ("created_at", "name", "reps", "updated_at", "weight", "workout_id") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["created_at", Sun, 07 Apr 2013 18:13:45 UTC +00:00], ["name", "lunge"], ["reps", 20], ["updated_at", Sun, 07 Apr 2013 18:13:45 UTC +00:00], ["weight", 30], ["workout_id", 64]]
(0.6ms) COMMIT
(0.4ms) BEGIN
(0.2ms) COMMIT
Redirected to http://localhost:3000/users/5/workouts
Completed 302 Found in 21ms (ActiveRecord: 3.5ms)
notice Unpermitted parameters: exercise.
Does anyone know why this is happening? I am super stumped. Any help would be super awesome. I might try and create a new rails 4 app and test these associations out there if no one has any ideas.
回答1:
In a rails 4 app you'll need to switch over your mass assignment strategy to use strong parameters. It means removing attr_accessible from your models and placing them in your controller. That's what your log is telling you on lines 6-7.
With nested attributes the workout_params in your controller will want to look something like this:
private
def workout_params
params.require(:workout).permit(
:id,
:next_attribute,
:next_attribute,
exercises_attributes: [
:id,
:next_attribute,
:next_attribute
])
end
There are a variety of resources out there for more information on strong parameters - here's one from Ryan Bates: http://railscasts.com/episodes/371-strong-parameters
来源:https://stackoverflow.com/questions/15866013/rails-4-0-beta-fields-for-not-accepting-pluralized-model-name-in-one-to-many-as