I have a Post, to which a migration adds a new attribute and table column short_url
. This attribute is either provided by the user, or, if left blank, automatically created:
class Post < ActiveRecord::Base
before_create :create_short_url
private
def create_short_url
if short_url.blank? || already_exists?(short_url)
write_attribute :short_url, random_string(6)
end
end
def random_string(length)
#innards are irrelevant for this question
end
end
In the migration, I want to run through all posts and have the short_url created and saved.
problem: Post.find(:all).each {|post| post.create_short_url}
in the self.up
is not possibl开发者_C百科e, due to the private scope of the create_short_url method.
problem: Looping through posts and update!
-ing them does not invoke the before_create :create_short_url
, because it is not before create. Once migrated, I prefer to not have any before_update
hooks in place: I don't need to change anything on update.
How would you tackle this? Copy over the random_string()
and associated methods to the migration? Add specific migration helper methods to the Post
?
Just use the Object method send
(it doesn't check protected/private).
Post.all.each do |post|
post.send :create_short_url
post.save!
end
An alternative would be (but that could interfere with other migrations running in the same Ruby-process after that):
Post.before_save :create_short_url
Post.all.each(&:save!)
Visibility tip: Most of the time what you really mean is protected
(see here). I recommend to use protected
instead of private
in this case.
精彩评论