A controller method includes:
#organization = Organization.find(params[:description])
check_expiration_date(#organization)
if #organization.update_attributes(subscription: true,
actioncode: session[:actioncode_id],
subs_exp_date: expiration_date)
...
private
def check_expiration_date(org)
expiration_date = Time.zone.now + 366.days
end
On the development server this generates the error below, referring to the line subs_exp_date: expiration_date:
undefined local variable or method `expiration_date' for #<OrganizationsController:0x007f36cd01d2a8>
Any ideas what might be causing this error? My idea was that check_expiration_date is executed first and thus sets the variable expiration_date.
It should be like this:
if #organization.update_attributes(subscription: true,
actioncode: session[:actioncode_id],
subs_exp_date: check_expiration_date(#organization))
If you see your code, expiration_date is a variable inside method check_expiration_date which limits its scope only to that method. Hence you cannot use variable expiration_date outside check_expiration_date.
Other way can be defining expiration date as an instance variable. Here:
def check_expiration_date(org)
#expiration_date = Time.zone.now + 366.days
end
and then
if #organization.update_attributes(... subs_exp_date: #expiration_date)
Key here is:
Contrast the scope of a local variable with that of an instance
variable: the instance variable is bound to the specific instance of
the class. By binding itself to the entire object, an instance
variable makes itself available to every method of the object.
It's because you set local variable expiration_date, it is visible only in current scope defined by method body. If you want to make this variable 'visible' also after method execution, you can set it instance variable:
#expiration_date = Time.zone.now + 366.days
and use it:
subs_exp_date: #expiration_date
For more info about Ruby variable scopes, you can go here:
http://www.techotopia.com/index.php/Ruby_Variable_Scope
or here:
Difference between various variables scopes in ruby
Solution 1:
Change this code:
check_expiration_date(#organization)
to:
expiration_date = check_expiration_date(#organization)
Solution 2:
Change:
def check_expiration_date(org)
expiration_date = Time.zone.now + 366.days
end
to:
def check_expiration_date(org)
#expiration_date = Time.zone.now + 366.days
end
and then:
if #organization.update_attributes(subscription: true,
actioncode: session[:actioncode_id],
subs_exp_date: #expiration_date)
Reason: You're trying to access expiration_date, which is a local variable whose scope is limited to check_expiration_date method and hence ruby is looking for a method instead of a variable. So, you need to make it an instance variable or create a local variable from the returning object of check_expiration_date method to get it working.
You are calling a local variable instead of instance variable. Its about variable scope. There are 2 options to get proper value for subs_exp_date
Convert local variable to instance variable
#expiration_date = Time.zone.now + 366.days
Another option to call method directly
subs_exp_date: check_expiration_date(#organization)
Related
I'm new to ruby rails, and I'm struggling to understand what the purpose of instance variables are.
What is the point of making a variable into an instance variable?
Basically why would I do this:
class User
def initialize(var1)
#name = var1
end
end
over this:
class User
def initialize(var1)
name = var1
end
end
And in what types of situations would I want to use an instance variable over just a regular variable?
The practical use for this is that if you need a variable to persist across function calls, make it an instance variable.
after you define the instance variable, you can call the value of this on another function and you will have the value.
In general an instance variable is local and persisted inside an instance of an object, whereas a local variable is only local and persisted inside a function/object/block scope.
in your example if you have another method on your user class, you can use the value of #name on that other method, but coulnd't use var1 outside of initialize method.
class User
def initialize(var1)
#name = var1
end
def greetings
"hello #{#name}"
end
end
class People
def age
#age
end
def age= age
#age = age
end
end
def show people
age = people.age || '22'
p "Hello, my age is #{age}"
end
people = People.new
show people
=> 'Hello, my age is 22'
age
=> NameError: undefined local variable or method 'age' for main:Object
user.age = 21
greet people
=> 'Hello, my age is 21'
#age
=> nil
Notice that both variable types are local to a specific context though. #age is defined within the people instance, so when you call people.age you are calling the age function in the age instance, in which #age is defined. age is only defined in the show function, so when you call p "Hello, my age is #{age}" you are able to get a value for age because you are within the scope in which it is defined.
Because your instance variable will be accessible to your view code, including within forms and passing data to paths. That's probably the most common, practical use case for them. In your example, I could do the following:
<p>User: <%= "#{#name}" %></p>
And, instead of seeing "#name" in my corresponding paragraph in the rendered H.T.M.L, you'd see the value of that instance variable - whereas the inverse:
<p>User: <%= "#{name}" %></p>
...will probably result in an ActionView error, since "name" is undefined, according to it.
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
I recently started learning ruby and i am confused between instance variable and local variable and class variable. so , i recently written code which will find the largest palindrome in 1000 prime numbers.
code is:
def prime_large(number)
arr_prime = []
Prime.each(number) do |x|
new_arr_prime = arr_prime.push(x.to_s)
updated = new_arr_prime.select { |y| y.reverse == y }
end
p updated.max
end
p prime_large(1000)
error i got is:
undefined local variable or method `updated' for main:Object (NameError)
I know that updated is a local variable of prime so i can't access it outside it but i changed the code by replacing it with #updated as below:
def prime_large(number)
arr_prime = []
Prime.each(number) do |x|
new_arr_prime = arr_prime.push(x.to_s)
#updated = new_arr_prime.select { |y| y.reverse == y }
end
p #updated.max
end
p prime_large(1000)
after changing it , i got the output:
"929"
"929"
in my code , without creating a class how my instance variable ( #updated) is working . i am confused between local and instance variable . can anyone please explain me the differences and how they work ?
In your first example you created a local variable updated, that is only accessible within the scope of the block it is defined in. Meaning, it is available only within Prime.each(number) do end block.
In your second example you created instance variable #updated.
without creating a class how my instance variable ( #updated) is
working
It is because in Ruby everything occurs in the context of some object. Even though you did not created a class, you are being in the top-level context, in the context of object main.
Thus, any instance variables defined within top-level are instance variables of this object main.
So going back to your issue, to overcome it you'll want to just define the updated local variable outside the Prime.each(number) do end block:
def prime_large(number)
arr_prime = []
updated = nil # initialize local varialbe
Prime.each(number) do |x|
new_arr_prime = arr_prime.push(x.to_s)
updated = new_arr_prime.select { |y| y.reverse == y } # assign new value
end
p updated.max
end
p prime_large(1000)
To test it you can open irb or pry and check it yourself:
self # the object in the context of which you are currently
#=> main
self.class # main is an instance of class Object, any methods defined
# within main are added to Object class as instance methods
#=> Object
instance_variables # list of it's instance variables, none yet created
#=> []
#variable = 1 # create and instance variable
#=> 1
instance_variables # now created variable occurs in the list of current object's instance variables
#=> [:#variable]
def hello; :hello end # define method
#=> :hello
self.class.public_instance_methods(false) # list instance methods defined in Object
#=> [:hello]
What you now want to read about is lexical scopes in Ruby.
I've a problem with the instance_variable_get method cause it's always returns nil object with one of my object instance.
Here is my code:
logger.info "ASDF: " + #d_tree.inspect
logger.info "ASDF: " + #d_tree.instance_variable_get(:#content);
and the output is:
ASDF: #<DTree id: 11, parent_id: nil, content: "bababababa", subsidiary_info: "", deep_info: "blabla", title: "hello", direction: 1, created_at: "2010-10-26 19:27:32", updated_at: "2010-11-01 23:14:31", color: 2, cell_color: 2, howtoinfo: "howtoinfooo", textinfo: "textInfooo", locationinfo: "locationInfoooo", productinfo: "productinfoooo">
TypeError (can't convert nil into String):
/app/controllers/d_trees_controller.rb:38:in `+'
According to the inspect the object seems to be fine, but the instance_variable_get returns a nil object
Thanks for your help!
instance_variable_get(arg)
It should return the value of the instance variable or nil if the instance variable is not set.
for example
we define the following class
class Velpradeep
def initialize(mark1, mark2)
#m, #s = mark1, mark2
end
end
During creation of the object of the class
obj = Velpradeep.new(98,96)
Then we can access the instance variables by using :
irb(main):046:0> obj.instance_variable_get(:#m)
=> 98
Access the undefined instance variables defined in the initialize method
irb(main):047:0> obj.instance_variable_get(:#p)
=> nil # provides nil bcz the instance variable is not defined
If you want to access the variable before you need to set the instance variable using
instance_variable_set()
example :
irb(main):048:0> obj.instance_variable_set(:#p, 99)
=> 99
Then we can use, it will return the value of the instance variable....
irb(main):049:0> obj.instance_variable_get(:#p)
=> 99
Although it's considered bad form to grab instance variables like this directly, as using attr_accessor is the preferred method, the problem in this particular instance is that there is no instance variable called #content. What you have appears to be an ActiveRecord attribute.
These are fetched using a different mechanism:
#d_tree.attributes[:content]
Generally this is even a little redundant as this will needlessly create a copy of the attributes hash. The typical way to access is:
#d_tree.content
These values are actually located in the #attributes instance variable managed by ActiveRecord.
instance_variable_get returns nil if the variable is uninitialized (or if it has been set to nil, of course).
So, obviously, #content hasn't been initialized yet.
Why it hasn't been initialized is impossible to tell, since you haven't shown us any actual code yet.
It looks like #d_tree might be an ActiveRecord object, in which case the solution is rather simple: ActiveRecord objects don't keep their state in instance variables, they are backed by a database.
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.