问题
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