If a method only does something if a condition is true, should I indicate that in the method name? - naming-conventions

Let's say I have this setup in Ruby on Rails:
class A < ActiveRecord::Base
after_create :perform_some_action
#...
private
def perform_some_action
if some_condition_met?
#take some action
end
end
Should I add something to the method name, perform_some_action, to indicate that it depends on a condition?

Definitely, yes, because your condition check is inside the method.
This way, when calling your method from outside, the code will look self-explanatory. If not, when you read your call it will give you the impression that take_some_action is performed whithout any condition.
However, if 37 conditions are required inside your method, perhaps it's the signal that this method should be split up in several smaller ones.

Related

Defining onchange methods in odoo if on_change is defined on the model

I'm trying to define an onchange event on the field amount and line_cr_ids.amount on account.voucher but any definition like this:
#api.one
#api.depends('line_cr_ids', 'line_cr_ids.amount')
def _line_amount_onchange(self):
...
Or
#api.one
#api.onchange('amount')
def _onchange_amount(self):
...
Are never called, I noticed that a on_change parameter is defined on those fields in the view. Does it means the only way to get the onchange is to redefine the one already defined?
Yes, you need to redefine the on_change method called by the view.
Or change the view itself removing it as attribute.
Ok, so I solved my problem as I didn't want to remove the on_change attributes... There is a better and more stable way of working than using the api.onchange decorator for now. I guess the decorators could get more stable over time but in my case it didn't fit at all. It would get called and sometimes it wouldn't... Children of object do not have access to parent object because the ORM doesn't allow it... ask me why I don't know...
That said the holy grail is to override the onchange method on the object.
I noticed that whenever something happens, it would call the onchange method on my account.voucher object.
So the solution is to create a method:
class AccountVoucher(models.Model):
...
#api.model
def onchange(self, ids, values, field, fields):
result = super(AccountVoucher, self).onchange(
values, field, fields
)
#...
# do whatever you want here change result and return it
#...
result
This way, all changes are visible and it never miss. It also call other onchange when calling super so you don't miss anything. If you need to use decorators anyway, it shouldn't stop anything from working. In other words... while overriding onchange, you're getting at the root of the problem and nothing stops you from getting things done.

Generating attribute methods - any bad side effects?

In rails, if I want to override an attribute method, eg. a setter, or getter etc, I might need the instance method to be defined.
However, activerecord does not define attribute methods until an instance is first synchronized.
This can be seen in:
class MyModel < ActiveRecord::Base
end
MyModel.attribute_methods_generated? # => false
MyModel.instance_method(:a_db_column)
# => NameError Exception: undefined method `a_db_column' for class `MyModel'
MyModel.new # implicitly calls define_attribute_methods
# MyModel.define_attribute_methods # can also use this instead of MyModel.new
MyModel.attribute_methods_generated? # => true
MyModel.instance_method(:a_db_column)
#<UnboundMethod: MyModel(#<Module:0x000000030a20a0>)#__temp__>
Is there any problem that could occur in calling define_attribute_methods early? Even doing something like:
class MyModel < ActiveRecord::Base
define_attribute_methods
# is there any code here which might cause problems?
end
Why do you need the instance method to be defined ? From what I understand, you're trying to add/override an instance method, so when you call this method, define_attribute_methods would have been called since an instance was created.
Tell me if I get you wrong.
From the information you provided it seems like you want to patch the methods generated by ActiveRecord on a model. Instead of triggering ActiveRecord's method generation, why not patch the define_attribute_methods to call your patching method after it has completed?

Kaminari doesn't work If my query is in the model

I have my mongoid query in the model
def self.get_result collection_name, hash_params, page, per_page
self.collection_name = collection_name
#result_pg = self.where(hash_params).page(page).per(per_page)
end
I have it here because my collection names are passed as parameters and I don't have models for all my collection. Instead I have one model and I set its name dynamically based on the request parameter.
My controller code
Collection.get_result params[:state], hash_param, params[:page], params[:per]
My View code
<%= paginate #result_pg %>
When I use the above code I get
undefined method `current_page' for nil:NilClass ERROR
I think the variable is being lost when you call it in the model. Instead, have it return the object back to you like so:
return self.where(hash_params).page(page).per(per_page) // put this in your model
Then, I'm the controller, connect the pieces:
#result_pg = Collection.get_result params[:state], hash_param, params[:page], params[:per]
// in your controller like so
Right now, the controller isn't setting #result_pg, that is why it is nil and you are getting the nil error. Try this and let me know if that worked out for you.
Updated
Ok, as for the reason this happens. When Rails loads a controller, the variables that you declare with a # symbol, like #bologna will be passed to the view and something will be done with them.
On the other hand, you are not technically declaring and instantiating that variable in the controller, you are doing it in the model, as per your source code that you posted above. Declaring the variable there can be done but it isn't useful because the controller has no idea that it even happened. When you tell the Class Collection to perform a method, usually you have that method return something back to you, if you don't, then the variable is lost.
It is similar to me asking someone to go to the store and buy me some groceries, you did the right things, giving the method all the information it needed, passing it the right variables to do its job correctly, but not telling it to actually come back with them, is where the error occurs. In your method, the groceries get purchased at the store and left there. The revised function I wrote for you tells it return with the groceries and put them in the variable #result_pg. The variable is declared in the Controller like it is supposed to be.
So in short, anything you want to have accessible in the view, needs to be declared in the controller. And anytime you want something back from a method, always have it return the information to you.
Also, it isn't entirely necessary to even have the method call to the Class Collection. In a project of my own where I use Kaminari, I just simply do the whole call from in the controller like so:
#notes = current_user.notes.page params[:page]
// My Application has :users that have_many :notes
So you could simplify it that way if you want, but the method that I suggested that fixes it the way you are doing it will work too, however you prefer.
I hope my explanation helped and wan't too long winded.

Rails 3: Best location for reusable function called aftersave

My app has points / awards that can be achieved after a number of actions take place, which generally trigger when a record has been added (completing a mission, etc.)
I wrote a fairly involved function that audits all of the data, and awards the proper amount of points, user ranking, etc. This needs to be called after each one of these records is saved.
I know I can use Observers to call the function after a number of model saves, but I am unclear on where exactly the put said function, and how to call it.
Much appreciated in advance!
Observers usually go in app/models/. You can automatically generate an observer class for a model with the command rails generate observer YourModel. This will generate the file `app/models/your_model_observer.rb'.
By the way, aftersave is not a very descriptive method name. If it does a lot of things it's better to break it up into several methods each of which do one thing, and give each a descriptive name, e.g.:
class YourModelObserver < ActiveRecord::Observer
def after_save your_model_instance
calculate_points your_model_instance
assign_awards your_model_instance
end
private
def calculate_points inst
# ...
end
def assign_awards inst
# ...
end
end

Create callback executing foobar twice

My model looks like this:
after_create :foobar
after_update :foobar
def foobar
update_attributes(:foo => 'bar')
end
Whenever I create an object. It calls foobar (after_create callback). But it also automatically triggers the after_update callback.
Basically, when I create an object its calling foobar twice.
How can I prevent this?
In after_create you're calling update_attributes() which triggers the after_update callback.
Basically you're calling it twice. You need to figure out what the proper flow is for your program, and make it such that foobar only gets called once. Right now, the code you've written is executing as designed.
One suggestion would be using before_[action] attributes instead to modify the fields in the incoming object. That way the object only gets saved once. The way you've written it, new objects get saved twice - once when they're created, and once when they're updated via update_attributes.
I see that this is example code, but I'm not sure how, in after_update, since you explicitly make ANOTHER update, how this isn't getting wrapped up in an infinite loop. Might be able to give a better answer if you post actual code.