Reputation: 361
I want a validation to run before a record gets updated. I know of before_update
but I pretty much copy and pasted the first codesnippet out of the api docs.
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
My stripped down model looked then like
class User < ActiveRecord::Base
attr_accessible :email
validates :email, :presence => true
before_save(:on => :update) do
puts "******** before_save on => :update ********"
# do something
end
end
if I go into the console and do create a new entry this callback is being executed on a SQL insert call.
irb(main):001:0> User.new(:email => "[email protected]").save
(0.1ms) begin transaction
******** before_save on => :update ********
SQL (29.1ms) INSERT INTO "users" ("created_at", "email", "first_name", "last_name", "updated_at") VALUES (?, ?, ?, ?, ?) [["created_at", Fri, 30 Mar 2012 00:26:33 UTC +00:00], ["email", "[email protected]"], ["first_name", nil], ["last_name", nil], ["updated_at", Fri, 30 Mar 2012 00:26:33 UTC +00:00]]
(433.1ms) commit transaction
=> true
irb(main):002:0>
I would have expected to see this only on an update call. Can anybody sheed some light on this?
[EDIT]
I just changed the callback into a function call with no change in the outcome. The callback is still executed on create.
class User < ActiveRecord::Base
attr_accessible :email
validates :email, :presence => true
before_save :my_before_update, :on => :update
private
def my_before_update
puts "******** before_save on => :update ********"
# do something
end
end
The output is the same.
Loading development environment (Rails 3.2.2)
irb(main):001:0> User.new(:email => "[email protected]").save
(0.1ms) begin transaction
******** before_save on => :update ********
SQL (28.2ms) INSERT INTO "users" ("created_at", "email", "first_name", "last_name", "updated_at") VALUES (?, ?, ?, ?, ?) [["created_at", Fri, 30 Mar 2012 02:28:45 UTC +00:00], ["email", "[email protected]"], ["first_name", nil], ["last_name", nil], ["updated_at", Fri, 30 Mar 2012 02:28:45 UTC +00:00]]
(131.2ms) commit transaction
=> true
Upvotes: 2
Views: 203
Reputation: 5593
The ActiveRecord::Callbacks don't support an :on
option...
From the Rails codebase, the only place that mentions handling an :on
option is in the validations module code in ActiveModel::Validations.
If you look through the ActiveRecord::Callbacks code, you'll see that there's no mention of :on
, nor does the ActiveRecord::Callbacks module include any of the ActiveModel::Validations module that will handle that option. There is an include for ActiveModel::Validations::Callbacks, but that will just provide the definitions for the before_
and after_
validations methods. However, the before_validation
and after_validation
callbacks will handle the :on
option as seen here in their definitions.
Upvotes: 3
Reputation: 2510
After a little more research, looks like you're right, it looks like you can pass :on => :update
to before_save
Maybe the issue comes from the block notation, try calling a function like this:
before_save :run_this_before_update, :on => :update
def run_this_before_update
puts "******** before_save on => :update ********"
# do something
end
Looks like a major reason to use this is the order in which Rails runs the callbacks, check out this most excellent article from pivotallabs http://pivotallabs.com/users/danny/blog/articles/1767-activerecord-callbacks-autosave-before-this-and-that-etc-
Upvotes: 0
Reputation: 80140
I'm pretty sure this is one of those areas that the Rails API has changed across versions. I do recall there being a way to pass :on
as an option to before_save
, just as I recall when you had to define an after_initialize
method (it wasn't available as a callback).
The current way is cleaner and more explicit.
If you do find that the current docs reference before_save(:on => :update)
, check out the new docrails Github repository where you can fork, change, and commit changes to the docs to be included (no pull requests necessary, or accepted).
Upvotes: 0