Am 22.07.2009 um 05:22 schrieb Learn By Doing:
save!
Thanks all for your help.
That sounds a lot like a validation, apart from saving the model in
the setter, which you shouldn’t do. From what I’ve gathered till now,
rails assumes you always work on a model as a whole, not on a single
attribute of the model. Another thing that you must always take care
of: If for whatever reason you decide to override any default method
or whatever of any API you use, make sure to always have the same
return value. Rails assumes a setter for an attribute of an
ActiveRecord object returns the attribute, heck even ruby assumes a
setter returns the object being set (or fail) for whatever object:
“”"
$ irb
x = 3
=> 3
x = :some_funky_symbol
=> :some_funky_symbol
x = some_variable_not_set
NameError: undefined local variable or method `some_variable_not_set’
for main:Object
from (irb):3
“”"
Anyway, if your some_stuff is a validation, i.e. doesn’t modify the
value of x, try this:
=== In the model ===
validate :some_validation
private
def some_validation
do some stuff with self.x
return true or whatever you want if it validates, return false or
an exception if not
end
=== In the controller ===
@my_model.x = “some_value”
@my_model.valid? # returns false if not all validations pass
@my_model.save # also fails (can’t remember if it returns false) if
not all validations pass, saves the model to the db if they do
(you obviously don’t need the valid? step, as it is called in save
too, but may this will help you in some way)
This separation between the data (model), and the business logic, i.e.
what you do with the data (controller) is just a consequence of the
strong MVC separation in rails.
One thing that worries me, is that I still don’t know if the
some_stuff you want to do with x also changes x. If it does, you
should separate the x processing part from the validation, put the
processing part in the public setter x=(val), and make it return the
processed x value, and put the validation as explained above.
For completeness’ sake: if some part of before_save fails, save will
also fail, although I’m not sure if a false return value will work, or
if you need to throw an exception.
In the end, I would urge you to rethink your MVC model: a setter
should return the object that gets to the internal attribute/object, a
setter should never save the object in the process (I’d even go as far
as saying that no function in the model should ever call save or
save!, because in 99% of the cases, it might bite your dog), the
validation of the attributes, be it sanity, existence or compliance to
some format, should occur on save, and the handling of failing
validations or a failing save should happen in the controller, not in
the model (maybe have a look at the defaults in a scaffolded object
and model: the update method in the controller for example fetches the
object, writes the parameters it got in the attributes of the object,
and the does if @the_object.save do some_happy_stuff else be_sad end).
I hope I was clear enough, but if there still is something unclear to
you, feel free to ask
HTH,
Felix