Validations misfiring in a form with multiple models
I'm building a web app that saves a user's goals and tasks, where a user has_many goals, and a goal has_many tasks. When I try to save a goal and task together, I keep getting validation errors saying "Tasks goal can't be blank" and "Tasks content can't be blank," even though they clearly aren't. I'm certain the problem isn't with the actual form, but with the goal controller's 'new' or 'create' code, but whatever I try, I can't seem to get it right. Any ideas on why the validations for the task model are misfiring? I've been working on this issue for too long and I'm about to give up. I've included the goal controller, goal model, task model, and debug info. If you need to see any other code, let me know.
Goal Controller:
def new
@title = "New Goal"
@goal = Goal.new
@goal.tasks.build
end
def create
@user = current_user
@goal = @user.goals.build(params[:goal])
@task = @goal.tasks.build(params[:goal][:task])
if @goal.save
flash[:success] = "Goal created!"
redirect_to user_path(@user)
else
render 'new'
end
end
Goal Model:
# Table name: goals
#
# id :integer not null, primary key
# user_id :integer
# content :string(255)
# completed :boolean
# completion_date :date
# created_at :datetime
# updated_at :datetime
#
class Goal < ActiveRecord::Base
attr_accessible :content, :completed, :completion_date
belongs_to :user
has_many :tasks, :dependent => :destroy
accepts_nested_attributes_for :tasks
validates :user_id, :presence => true
validates :content, :presence => true, :length => { :maximum => 140 }
end
Task Model:
# id :integer 开发者_开发问答 not null, primary key
# goal_id :integer
# content :string(255)
# occur_on :date
# recur_on :string(255)
# completed :boolean
# completion_date :date
# created_at :datetime
# updated_at :datetime
#
class Task < ActiveRecord::Base
attr_accessible :content, :occur_on, :recur_on, :completed
belongs_to :goal
validates :goal_id, :presence => true
validates :content, :presence => true, :length => { :maximum => 140 }
end
Debug Dump after an unsuccessful save:
--- !map:ActiveSupport::HashWithIndifferentAccess
utf8: "\xE2\x9C\x93"
authenticity_token: NF/vVwinKQlGAvBwEnlVX/d9Wvo19MipOkYb7qiElz0=
goal: !map:ActiveSupport::HashWithIndifferentAccess
content: some goal
tasks_attributes: !map:ActiveSupport::HashWithIndifferentAccess
"0": !map:ActiveSupport::HashWithIndifferentAccess
content: some task
commit: Submit
action: create
controller: goals
This is a problem with nested attributes. You cannot validate the presence of the encapsulating model from the nested model (in your case, you cannot validate the presence of goal_id from Task). When validations are run the goal is not yet saved, and thus has no id, so it is impossible to assign it.
You can either eliminate the validation that is causing the problem, or not use the built-in nested attributes. In the latter case, you would need to add your own logic to first save the goal and then create any nested tasks.
Bummer, huh? I wish someone would come up with a good solution for this...maybe I'll work on it if I ever get some free time.
精彩评论