I have this simple rails code and something weird is happening. As you can see params.nil? is true and it's still calling the else part. What am I missing here?
Pry Session
5: def build_resource
6: binding.pry
7: if params.nil?
8: model_class.new
9: else
=> 10: params = params.merge(dealer: {})
11: model_class.new(dealer_params)
12: end
13: end
[3] pry(#<Admin::DealersController>):1> params.nil?
true
No, Its not a pry issue. You just cant reassign params to params. Try using different variable. This should work fine.
You can use as
dealer_params = params.merge(dealer: {})
updated answer
Digging Deeper inside Rails. Have a look at this.
class Parameters
cattr_accessor :permit_all_parameters, instance_accessor: false, default: false
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
.....
end
Simple Explanation: params are responsible for carrying value which you permit inside your controller, but its resigning it will return false or nil. You can study about these topics in dept you get to know.
https://apidock.com/rails/Class/cattr_accessor
That's why when you declare new variable the value of params => (object) is assigns to it. But when you do the same thing with params or method that return an object this will give nil.
SAME Answer: you just can't reassign params to params.
So, this answer my question (https://stackoverflow.com/a/1335890):
The params which contains the request parameters is actually a method call which returns a hash containing the parameters. Your params = line is assigning to a local variable called params.
After the if false block, Ruby has seen the local params variable so when you refer to params later in the method the local variable has precedence over calling the method of the same name. However because your params = assignment is within an if false block the local variable is never assigned a value so the local variable is nil.
If you attempt to refer to a local variable before assigning to it you will get a NameError:
irb(main):001:0> baz
NameError: undefined local variable or method `baz' for main:Object
from (irb):1
However if there is an assignment to the variable which isn't in the code execution path then Ruby has created the local variable but its value is nil.
irb(main):007:0> baz = "Example" if false
=> nil
irb(main):008:0> baz
=> nil
Related
I am unfortunately running an application on Rails 2.3.18 and am seeing strange behavior with the params variable within the controllers. There are some areas of the app that (for some reason) assign params to itself or an empty hash by default.
params = (params || {})
Now the params variable is initialized to be the request parameters so it should evaluate to true in a logical expression. However, in this case params gets set to {}. Why exactly is this happening?
I don't have a Rails 2.3 app to play around with but params in a controller is actually method but saying params = ... creates a local variable that shadows the standard params method. For example, try this in irb:
def x
puts 'x is being called'
{ :where_is => 'pancakes house?' }
end
x = x || { }
and you'll see that x is { } and the x method never even gets called. The code that says:
params = (params || {})
is effectively doing this:
params = nil # Declare a local variable and initialize it to nil
params = params || { }
# -------^^^^^^ the local variable above, not the method
However, if you force the RHS params to be a method call:
params = params() || { }
# -------------^^
then it should call the method but you'll still have the local params variable on the LHS of the assignment.
I think you need to figure out why the code is doing params = params || { } and refactor it so that it isn't necessary. Are these controller methods trying to work when they're not actually in a controller? Are they depending on dodgy edge cases in older versions of Ruby? Was that code added cargo-cult style by someone copying mystery code from a blog they didn't understand?
Even though Rails.application.config.trackable_models returns a full array, defined?(Rails.application.config.trackable_models) returns nil.
Rails.application.config.trackable_models # => ["NewsItem", "ContentPage", "Event"]
defined?(Rails.application.config.trackable_models): # => nil
Setting a local variable in the same way is fine:
foo = ["x"]
defined?(foo) # => local-variable
What is the proper way to check for the existence of a config variable if not "defined?"?
If you want to check the method is defined in the literal sense, use respond_to
Rails.application.config.respond_to?(:trackable_models)
If you want to check if the method returns something other than nil, you have some options:
tm = Rails.application.config.trackable_models
tm.nil?
tm.presence || 'default value'
tm.present?
tm.blank?
I have an issue storing the result of a query in a controller:
payments = Payment.select("SecurityKey").where("VendorTxCode = '%#{params[:VendorTxCode]}%'").limit(1)
payments.each do |payment|
security_key = payment.SecurityKey
end
Later when I use security_key, I get an error that it is undefined. However, when I run this in the rails console as:
payments.each do |payment|
puts payment.SecurityKey
end
#=> df4g5ds6
How can I store this result in a variable for use later on as my method is not working?
It looks like you need to define your variable before your each do block. Try storing the keys into an array as such:
payments = Payment.select("SecurityKey").where("VendorTxCode = '%#
{params[:VendorTxCode]}%'").limit(1)
security_key = []
payments.each do |payment|
security_key << payment.SecurityKey
end
And then you can access the keys like security_key[0], etc.
First off, since you're limiting your search to 1, you don't really need to use a loop. Just do:
security_key = payments.first.SecurityKey
Other than that, what do you mean by "Later when I use security_key, I get an error that it is undefined.". Where are you using it? Are you using it within that method? Then it should be there. The only reason why it may not be, is if your query returned nothing. If your query returned an empty collection, then the loop will never happen, and the variable will never be created or set.
Try this:
payments = Payment.select("SecurityKey").where("VendorTxCode = '%#{params[:VendorTxCode]}%'").limit(1)
p payments.first # Will output nil if it's not there
If you get outputted nil, then you know that's what's happening. You'll then have to modify your code to check for nil and respond/behave accordingly.
If by 'later' you mean accessing it from helpers or views, you need to make the variable an instance variable instead of local: #security_key.
You're defining security_key as a local variable within the scope of the do...end block you're passing to that each statement. In other words, it's not available outside that block.
Here's an example in the Pry console.
[4] pry(main)> (1..10).each {|number| result = number}
=> 1..10
[5] pry(main)> result
NameError: undefined local variable or method `result' for main:Object
result defined inside the block is not defined or visible outside it.
[6] pry(main)> result = 0
=> 0
[7] pry(main)> (1..10).each {|number| result = number}
=> 1..10
[8] pry(main)> result
=> 10
Here, by defining result within the scope of the console session first I can now see the changes made to it within the block.
Does that make sense?
I'm using Ruby 1.8.7 with Rails 3.0.1 and am having a problem whose root cause appears to be the "Array === object" operation. I saw the same behavior before in a class of my own creation, and programmed around it by not using the "===" operator (I assumed that there was some flaw in my knowledge of Ruby, which is still rather limited). But now that it is happening inside ActionPack, I need to do something about it.
This surfaced when the FormHelper "fields_for" was not acting the way it should. The following view code snippet ("<% %>" removed to improve readability):
form_for #coupon do |f|
...
f.fields_for #coupon.participants do |cp|
...
end
end
gave the error "ActionView::Template::Error (undefined method `model_name' for Array:Class):"
inside the form_for helper method. I determined that it was executing the wrong branch of a "case" command, set a breakpoint and started testing. Here are the results:
/Library/Ruby/Gems/1.8/gems/actionpack-3.0.1/lib/action_view/helpers/form_helper.rb:1152
case record_or_name_or_array
(rdb:1) pp record_or_name_or_array.instance_of? Array
true
(rdb:1) pp Array === record_or_name_or_array
false
(rdb:1) pp Array.object_id
2148267660
(rdb:1) pp record_or_name_or_array.class.object_id
2148267660
This shows pretty definitively that, while "record_or_name_or_array" is definitely an array, "Array === record_or_name_or_array" is returning false.
BTW, in case you're suspecting that "#f.fields_for" is the wrong syntax, I tried it both with and without the "#f." and got the same result. I have also restarted RoR and my machine and the results remain unchanged.
Try this:
#coupon = Coupon.last
Array === #coupon.participants #=> false
Array === #coupon.participants.find(:all) #=> true
Association #coupon.participants is not an array, it is a proxy. The reason why #coupon.participants.class == Array is true is described in activerecord-3.0.9/lib/active_record/associations/association_proxy.rb:25
Added: Another interesting experiment would be #coupon.participants.superclass.
From the console (rails c) try running:
#coupon = Coupon.last
Array == #coupon.participants
If that call returns false, it is most likely that your associations are incorrectly setup (i.e. has_many :participants and belongs_to :coupon).
#coupon.is_a? Array should return true, #coupon === Array would mean #coupon was equal to the singleton instance of Array
I have the code sequence below in a rails controller action. Before the IF, params contains the request parameters, as expected. After it, params is nil. Can anyone please explain what is happening here?
if false
params = {:user => {:name => "user", :comment => 'comment'}}
end
Thank you.
The params which contains the request parameters is actually a method call which returns a hash containing the parameters. Your params = line is assigning to a local variable called params.
After the if false block, Ruby has seen the local params variable so when you refer to params later in the method the local variable has precedence over calling the method of the same name. However because your params = assignment is within an if false block the local variable is never assigned a value so the local variable is nil.
If you attempt to refer to a local variable before assigning to it you will get a NameError:
irb(main):001:0> baz
NameError: undefined local variable or method `baz' for main:Object
from (irb):1
However if there is an assignment to the variable which isn't in the code execution path then Ruby has created the local variable but its value is nil.
irb(main):007:0> baz = "Example" if false
=> nil
irb(main):008:0> baz
=> nil
See: Assignment - Local Variables and Methods in the Ruby docs.