问题
A doc has many articles and can have many edits.
I want to build an edit for each article up to the total number of @doc.articles. This code works with the first build (i.e., when no edits yet exist).
def editing
@doc = Doc.find(params[:id])
unbuilt = @doc.articles - @doc.edits
unbuilt.reverse.each do |article|
@doc.edits.build(:body => article.body, :article_id => article.id, :doc_id => @doc.id)
end
end
But when edits already exist it'll keep those edits and still build for the @doc.articles total, ending up with too many edits and some duplicates if only one article was changed.
I want to put some condition against :article_id which exists in both edits and articles in to say (in pseudocode):
unbuilt = @doc.articles - @doc.edits
unbuilt.where('article_id not in (?)', @doc.edits).reverse.each do |article|
@doc.edits.build(...)
end
Any help would be excellent! Thank-you so much.
回答1:
You are doing something weird here:
unbuilt = @doc.articles - @doc.edits
You probably want this instead
unbuilt = @doc.articles - @doc.edits.map(&:article)
This works if @doc.articles and @doc.edits are small collections, otherwise a SQL solution would be preferred.
-- EDIT: added explanation --
this piece of Ruby
@doc.edits.map(&:article)
is equivalent to
@doc.edits.map do |edit| edit.article end
the previous one is much more compact and exploits a feature introduced in ruby 1.9
It basically takes a symbol (:article), calls on it the 'to_proc' method (it does this by using the '&' character). You can think of the 'to_proc' method as something very similar to this:
def to_proc
proc { |object| object.send(self) }
end
In ruby, blocks and procs are generally equivalent (kindof), so this works!
来源:https://stackoverflow.com/questions/17269052/rails-build-for-difference-between-relationships