开发者

relationship problem in views/controller

I have two models (simplified) similar to this:

RECIPE (has_one video)

  • id
  • name
  • descripion

VIDEO (belongs_to recipe)

  • id
  • link
  • recipe_id

In RecipesController#new I render a view for creating a resource. I use form_for @recipe, with all the regular f.helpers

The thing is that I need a field to fill in the link attribute, and that belongs to a different object (video). So, since the f.helpers prefix everything with resource[field], I used a regular text_field_tag :link.

Everything went smooth so far. In RecipesController#create I do:

@recipe = Recipe.new(params[:recipe])

@recipe.video = Video.new(params[:link])

to assign a video to the recipe.

After this I do the usual @recipe.save and this is where I am stuck.

I expected that if video contains any errors, the recipe wont save and that I will be able to use @recipe.errors object to obtain all the errors (the ones from video too).

But not only does recipe save, @recipe.errors does not contain messages from 开发者_如何学编程video. I was using a (partial "errors", :object => @recipe) to list all messages, but this won't pick up the ones that got trigged by the video object.

I tried various things, for example, inside the partial I had a conditional that originally checked:

if object.errors.any?
 object.errors.full_messages ...
end

I swapped it to:

if (object.errors.merge!(object.video.errors)).any? but it didn't work sadly.

What should I do in such situation? How do I prevent @recipe from saving when a video has errors, and how do I list them together seamlessly?


Dealing with nested objects takes a little bit of work, but it isn't that hard. Since Rails 2.3, there has been the concept of "nested attributes" and "nested object forms" (see: http://guides.rubyonrails.org/2_3_release_notes.html#nested-attributes and http://guides.rubyonrails.org/2_3_release_notes.html#nested-object-forms).

Basically, this allows you to do something like this:

<% form_for @recipe do |f| %>
  <%= f.text_field :name %>
  <%= f.text_field :description %>
  <% f.fields_for :video do |v| %>
    <%= v.text_field :link %>
  <% end %>
<% end %>

As you see, the code is telling the form that there are fields_for a :video object within the recipe. You can then alter your recipe like so:

class Recipe < ActiveRecord::Base
  has_one :video
  accepts_nested_attributes_for :video
end

This code tells ActiveRecord that you might pass in attributes for the video object in with the recipe. So now, all you have to do is. . .

Recipe.create(params[:recipe])

. . . and it will create the recipe and the video records since your form has the video information and the Recipe class accepts_nested_attributes_for :video.

--

Just to clarify a couple things about your code. You're passing in params[:link] to Video.new. Video.new doesn't expect a string, it's expecting a hash of attributes. So, you're calling. . .

Video.new("example.com/video_file.mp4")

. . . when you really mean to be passing in. . .

Video.new(:link => "example.com/video_file.mp4")

Without being a hash, ActiveRecord doesn't know which attribute you're trying to set via "new". You could also do. . .

v = Video.new
v.link = params[:link]

. . . and set the attribute that way. Plus, depending on what else was in the controller, you may not be assigning the recipe_id to the video and you might not be calling @video.save. Sometimes the coolness of ActiveRecord can make it seem like those things don't have to happen - and if you're using something like accepts_nested_attributes_for you don't need to do those things. However, if you want to manually do it, you have to make sure to save them all, assign the associations, check both objects for errors, and manage the transaction.

--

The Rails documentation on this isn't bad and goes over a lot of it: http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

Ryan Daigle also has a nice blog post about it: http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜