ruby dynamic method passing a value - ruby-on-rails

How do I pass a value to a dynamic method name that's called on a rails model?
#model.send(dynamic_method_name.to_sym,123)
This gives the error:
wrong number of arguments (1 for 0)
If I were to use the same method like this though:
#model.post_id = 123
then it works.
So there is a "setter" method for the method post_id (and therefore the dynamic method name).
How do I pass a value to this setter when the method is dynamic?
thanks!

You need to add the "=" to your dynamic_method_name. In ruby, :post_id is the name of the getter, and :post_id= is the name of the setter. The .to_sym isn't strictly necessary so you can do this:
#model.send("#{dynamic_method_name}=", 123)

Related

How to call a method with question mark via send in ruby

I have methods generated for a list of symbols. One of the methods includes a question mark in its definition. I want to invoke such a method with a variable holding that symbol.
Suppose we generate a method for :check_element symbol and the corresponding method signature would look like.
class A
def check_element?
end
end
Now I have a variable flag = :check_element and I'm unable to call the method like A.send(flag)
but A.send((flag.to_s + '?').to_sym) works.
I'm thinking if there is a better way to achieve this.
There is no need to translate the method name argument to a symbol because send accepts a string too. That allows simplifying your example to
A.send(flag.to_s + '?')
Which can be simplified using string interpolation to
A.send("#{flag}?")

Rails params "method" isn't a method, is it?

In the Rails documentation, the following example is given as a way to display what the server receives from a POST request:
def create
render plain: params[:article].inspect
end
In the subsequent description, the text states
The params method is the object which represents the parameters (or fields) coming in from the form. The params method returns an ActiveSupport::HashWithIndifferentAccess object.
While I understand that all methods are objects, I don't understand how it's correct to refer to the params object as a method. Specifically, the phrase "returns an ActiveSupport::HashWithIndifferentAccess object" suggests to me that there are two calls going on--what in python might look like:
params().__getitem__('article')
but I don't think that's what's actually going on.
The conversation around those lines also refers to params as a method, so I'm starting to think I must be missing something.
I'm new to Ruby, and while I understand that all methods are objects,
No, they aren't. Methods belong to objects (more precisely: methods are defined in modules, and executed in the context of objects), but they are not, by themselves, objects. (It is, however, possible to obtain a reflective proxy which represents the concept of a method by calling the method method, which returns a Method object.)
I don't understand how it's correct to refer to the params object as a method.
Because it is a method. Not an object.
What else would it be? Syntactically, it's obvious that it can only be one of three things: a keyword, a variable, or a method call.
It can't be a keyword, because Rails is just a Ruby library, and Ruby libraries can't change the syntax of the language (e.g. add or remove keywords). It can't be a variable, because in order for it to be parsed as a variable, the parser would need to have seen an assignment to it within the same block.
Ergo, the only thing it can possibly be, is a method call. You don't even need to know anything about Rails to know this. It's just basic Ruby syntax 101.
Specifically, the phrase "returns an ActiveSupport::HashWithIndifferentAccess object" suggests to me that there are two calls going on--what in python might look like:
params().__getitem__('article')
but I don't think that's what's actually going on.
That is exactly what is going on. You call the method params and then you call the method [] on the object that is returned by calling the method params.
This is in no way different from foo.bar: you call foo, then call bar on the return value of foo.
The params method is a method, returns a hash (which holds some details about parameters send to the app). Simplified it looks like this:
def fake_params
{ :controller => 'foo', :action => 'bar' }
end
You can call another method directly on the returned hash like this:
fake_params[:action] #=> 'bar'
params is a method defined in ActionController::Metal which returns the request.parameters object.
https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal.rb#L140

How to properly set an instance variable with instance_variable_set?

I was looking through the docs for instance_variable_set and saw that the sample code given does this:
obj.instance_variable_set(:#instnc_var, "value for the instance variable")
which then allows you to access the variable as #instnc_var in any of the class's instance methods.
I'm wondering why there needs to be a colon : before the #instnc_var. What does the colon do?
My first instinct is to tell you not to use instance_variable_set unless you really know what you are using it for. It's essentially a tool for metaprogramming or a hack to bypass visibility of the instance variable.
That is, if there is no setter for that variable, you can use instance_variable_set to set it anyway. It's far better if you control the code to just create a setter.
Try looking at accessors for the vast majority of your instance variable setting needs. They are an idiomatic way to have getters and setters for your instance variables "for free" without you having to write those functions.
If you really do need instance_variable_set, it allows the first argument to be a symbol which is the name of the instance variable to set. A colon is part of the Ruby language that is like a "symbol literal": when you type :foo, you've created a symbol with value foo, just like when you type "bar" directly into your code, you create a string literal with value "bar".

how is rails params hash made available to controller methods

I understand the rails params hash is available in my controller methods, but I'm trying to understand how that happens. Is it a parameter passed to the method? If so, how can we access it since controller methods don't have any declared arguments?
Its not a parameter, its actually just a 'getter' function, that is declared in https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/parameters.rb
So calls to params[:something] is really a method call which returns a hash, from which you access the http parameters.

How do I access the Activerecord setter I overrode?

I want to use a custom setter to do some formatting of my fields. In irb if I test the setter like:
o.field_name = "4"
I see that my custom setter is being referred to. But with this it is not:
o[:field_name] = "4"
I understand that in the first case this is a function call and in the second case we are just setting the attribute directly. But I don't completely see how the attribute can be set without going through our custom setter, I thought that was the point.
But my main question is that if var holds my field_name, I don't see how to dynamically refer to a.var and have it be interpreted as a.field_name. All I see to do is a[var] and this bypasses my setter.
Try a.send(var) where var = 'field_name'
That's the equivalent of a.field_name
o[:field_name] is like read_attribute(:field_name), thus is just reads the value as you said. It can be quite important in virtual attributes in order to bypass the stack too deep error. If you do a[:var], you just get its value. A virtual attribute refers to an attribute, if you are setting its value to another variable, you just get its value, not the object.

Resources