rails4 AR: Local var is declared in not executed code-block [duplicate] - ruby-on-rails

This question already has answers here:
Confusion with the assignment operation inside a falsy `if` block [duplicate]
(3 answers)
Closed 5 years ago.
In rails 4.2.5: Is it possible, that a locale var will be declared, even if it occurs in a not executed block?
See this example:
class Animal < ActiveRecord::Base
def test
# there is no local var `name`
puts "name " + name.inspect
puts "self.name " + self.name.inspect
if false
name = 'Hund'
end
# now there is a local var `name` (value `nil`)
puts "name " + name.inspect
puts "self.name " + self.name.inspect
end
end
To test it:
>> Animal.new(:name=>'Katze').test
name "Katze"
self.name "Katze"
name nil
self.name "Katze"
We just were very surprised, that name suddenly was nil.
For which reason does it behave like this? Is this wanted behaviour? So we must not rely on name, but using self.name in future?
(No question, one should use self.name = "Hund", but why is that local var declared.)
Thanks and regards, Phil

It's important to realize that when you call self.name you're not actually accessing a variable but rather sending a message to an accessor method
def name
#name
end
It's also important to know how the Ruby parser handles local variables, especially when inside a conditional. This is an excerpt from the Well-Grounded Rubyist Chapter 6.1.2
When the Ruby parser sees the sequence identifier, equal-sign, value,
as in this expression
x = 1
it allocates space for a local variable called x. The creation of the
variable—not the assignment of a value to it, but the internal
creation of a variable—always takes place as a result of this kind of
expression, even if the code isn’t executed! Consider this example:
if false
x = 1
end
p x # Output: nil
p y # Fatal Error: y is unknown
The assignment to x isn’t executed, because it’s wrapped in a failing
conditional test. But the Ruby parser sees the sequence x = 1, from
which it deduces that the program involves a local variable x. The
parser doesn’t care whether x is ever assigned a value. Its job is
just to scour the code for local vari ables for which space needs to
be allocated. The result is that x inhabits a strange kind of variable
limbo. It has been brought into being and initialized to nil. In that
respect, it differs from a variable that has no existence at all; as
you can see in the example, examining x gives you the value nil,
whereas trying to inspect the non-existent variable y results in a
fatal error. But although x exists, it has not played any role in the
program. It exists only as an artifact of the parsing process.
Given the above information, the first time you call name.inpspect in your code, the Ruby parser knows that no such local variable has been defined so it looks to see whether a method by that name exists (it does as it's provided by ActiveRecord) and calls that method - so in the first case name.inspect and self.name.inspect are both calling the same accessor method.
The next time you call name.inspect, you're actually calling the local variable name which the Ruby parser has initialized to nil.
The takeaway is that you should always use self explicitly. Hope this helps. Cheers.

This is a Ruby thing, not a Rails thing.
Ruby does not define a closed scope for if blocks.
You can get more details of the reason here: https://softwareengineering.stackexchange.com/questions/58900/why-if-statements-do-not-introduce-scope-in-ruby-1-9#answer-60413

Related

What is the point in Ruby's String#freeze method if one can still reassign a new value to the frozen variable?

I'm trying to understand the use of
# frozen_string_literal: true
in RoR and I understand the freeze method protects the frozen strings from modification up to some extend, but what's the point given that it's as easy to change the string as just reassigning the value? I would expect freeze to block reassignment too if the idea is protecting the variable from modification.
str = "string"
# => "string"
str.freeze
# => "string"
str.frozen?
# => true
str << "fails"
# Traceback (most recent call last):
# 4: from /Users/dev/.rvm/rubies/ruby-2.7.2/bin/irb:23:in `<main>'
# 3: from /Users/dev/.rvm/rubies/ruby-2.7.2/bin/irb:23:in `load'
# 2: from /Users/dev/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `<top (required)>'
# 1: from (irb):4
# FrozenError (can't modify frozen String: "string")
str = "stringfails... but this is fine?!"
# => "stringfails... but this is fine?!"
str
# => "stringfails... but this is fine?!"
I feel like I'm getting confused between freezing the string versus freezing the variable, but a lot of resources mention constants and compare the behaviour to them, so I'm unsure if the idea is to freeze the string assigned to the variable or the variable itself.
A variable is a pointer. freeze does not make the variable "unmutable" (such a thing would be a constant, not a variable), but disallows modifications on the object it points too. The object becomes a bit similar to a number or symbol, which you can't modify either, i.e. which is always kind of frozen:
a=:sym1
a=:sym2
You can assign something new to a, but you can not change :sym1 itself.
Now to the question what we can use it for, examples on how I use it:
If I know that an object should not be modified after a certain point in the lifetime of the program, I freeze it, and if - during a program error - it is being modified, I get an exception, which is useful for debugging.
Another example use is with Hash and Set objects. If you use a String as a hash key, or in a Set, Ruby creates a copy of this string, before it is entered in the Hash. This copying is not done if the string is frozen. In our application, we have many hashes, and ran into serious performance problems, because the heap was filled again and again with copies of the strings and garbage collection took a considerable amount of time. There were not so many different strings as such, but they were put into many (often temporary) hashes. As a solution, we implemented a special "Freezer" object, which contains one frozen instance of each string, and use these as Hash keys.
The general idea behind freezing objects is to make them immutable. This is a valuable trait to have in some situations. Say, you're making an API client, for example.
# frozen_string_literal: true
username = "sergio"
password = "password"
host = "https://example.com/api"
client = MyAPI::Client.new(host, username, password)
Here, once client obtained a reference to a frozen string, it can be sure that this string will never change (from the point of view of this client). So other code can't make host to point to another site or change the password to "bogus" and so on, and have client observe these changes.
With regular, unfrozen strings, you can mutate them in-place in a bunch of ways: gsub!, replace, etc. This affects all references.
This problem is much more pronounced with hashes and arrays, IMHO. In my experience, you mutate them in-place much more often. Like this, for example:
h[:foo] = :bar
ary[0] = 3.14
So if you want to make sure this hash or array never changes*, freeze it.
* caveat: freezing a hash or array only protects its immediate structure. Values in a hash and elements in an array are still mutable, you have to freeze them individually.
You can think of the variable like a sign that says: "oh you are looking for the string? it is over there" and it points to the string itself. So you have a "sign" (the variable) and the object itself (the string)
When you freeze, you freeze the object, not the sign that points to the object. So you can not change the frozen string, but you can still make that sign point to something else.
I have called name a variable that points to my object (a String holding my name)
name = "Pascal"
I can make the variable point to another object (your name)
name = "noname"
The String "Pascal" might still be somewhere in memory but I don't know where. It is lost and will get arbage collected at some point to free the memory.
I don't want anybody to change the value of the string, so i freeze it
name.freeze
But i still can point that variable into another direction
name = "Hondo"
Now there is a frozen String somewhere in memory containg "noname" but again, it is lost since we don't have any sign pointing to it. This frozen string will, if your program runs long enough), be garbage collected as well.
We can also have multiple variables pointing to the same object:
variable_a = "something"
=> "something"
variable_b = variable_a
=> "something"
variable_a.object_id
=> 70104549867280
variable_b.object_id
=> 70104549867280
object_id gives you an identifier of the object the variable is pointing to. It isthe same for vairable_a and variable_b so they are pointing to the same object.

Rails: difference between ENV.fetch() and ENV[]

What is the difference between these two syntax:
ENV.fetch("MY_VAR")
ENV['MY_VAR']
I've seen Rails 5 use both versions of these in difference places and can't figure out what the difference is (apart from the first one being more characters to type).
The ENV hash-like object is plain Ruby, not part of Rails. From the fine ENV#[] manual:
Retrieves the value for environment variable name as a String. Returns nil if the named variable does not exist.
and the fine ENV#fetch manual:
Retrieves the environment variable name.
If the given name does not exist and neither default nor a block a provided an IndexError is raised. If a block is given it is called with the missing name to provide a value. If a default value is given it will be returned when no block is given.
So just like Hash#[] and Hash#fetch, the only difference is that fetch allows you to specify the behavior if a key is not found (use a default value passed to fetch, default block passed to fetch, or raise an exception) whereas [] just silently gives you nil if the key isn't found.
In the specific case of:
ENV.fetch("MY_VAR")
ENV['MY_VAR']
the difference is that ENV['MY_VAR'] will give you nil if there is no MY_VAR environment variable but ENV.fetch('MY_VAR') will raise an exception.

What does it mean when a variable or method or constants has preceded with an underscore in Ruby?

What does it mean in Ruby when you see methods or variables with an underscore before them like this in Rails
submit_tag _('Enroll')
:notice => _('Update card.')
or
_session_id
Are most of these just conventions, or do they imply a functional difference in the behavior of the variables/methods?
There is no difference in bahavior. It is just convertion.
But let's have a closer look:
_('A string') is actually a method not a variable. The underscore method is defined by Gettext and translates a string.
#_foo is offen used to show other developers that there is something special about the variable, and therefore it should not be used. I saw that pattern a lot for variables that are used to cache values, like:
def expensive_operation
#_expensive_operation ||= begin
# long running code...
end
end
And the underscore is sometimes used to indicate that a variable is not used in a block. Like this:
a_hash.each do |_, value|
# do something with the value, not with the key
end
Those two cases are completely different.
The second looks like it is a local variable (although it might be a method call, it's impossible to tell without the context). Local variables that begin with an underscore will not generate an "unused variable" warning if they are unused, which is why they are used to indicate a variable that is intentionally not used (as opposed to a typo or pogramming error).
The first is a call to a method named _. What this method does, depends on the class of self at that point, you will have to look at the documentation for that class.
In IRb, _ is a method that returns the result of the last expression that was evaluated.

Understanding Ruby variables and symbols?

I am having some trouble understanding the syntax of variables and symbols in Ruby. I am reading a book called Agile Web Development with Rails 4. I am trying to learn both Ruby and Rails so that I can build websites.
The books and tutorials I have been reading sometimes have variables with the "#" symbol in front of them, and then some variables do not have the # symbol in front of them. What is the difference between them?
Also, I am getting confused with the colon. Sometimes I see variables where the colon is in the front, such as :order, and then I see variables where the colon is at the end, such as colon:. I do not understand what the colon is doing.
Please help me understand the Ruby syntax.
Variables starting with # are instance variables, "properties" in other languages. Whereas 'classic' variables are local to the scope of their method/block, instance variables are local to a specific instance of an object, for example:
class Foo
def initialize(bar)
#bar = bar
end
def bar
#bar # the variable is specific to this instance
end
def buzz
buzz = 'buzz' # this variable is not accessible outside of this method
end
end
You may also see variables starting with ##, which are class variables, and are accessible by every instance of the class and shared with every instance of the subclass. Usage of those variables is usually discouraged, primarily because subclasses share the variable, which can cause a lot of mess.
In Ruby everything is an object, classes are objects (instances of class Class), so you can also have class instance variables:
class Foo
def self.bar
#bar #we are in class Foo's scope, which is an instance of class Class
end
def self.bar=(bar)
#bar = bar
end
def bar
#bar # Foo.new.bar != Foo.bar
end
end
What you call "variables with a colon" are not variables. They are a particular type of string, called a symbol, that is immutable and optimized for quick identification by the interpreter, in fact, those are stored internally as pointers, so that :this == :this is a very quick operation.
This property makes them good candidates for hash keys because they offer quick retrieval or for "flags" to pass to a method; Think of them as a sort of loose constant that "stands for" what they say. Their immutability is also dangerous: All symbols ever created never get garbage collected; It's easy to create a memory-leak by creating thousands of symbols, so use them wisely.
UPDATE since ruby 2.2 symbols may be garbage-collected in certain cases (when no reference is kept and no comparison is needed)
Variables with an # symbol are instance variables. What this means is that they persist as long as the instance of the class they are declared in persists. So if you have a class called Message and each message has a variable called #subject, when you instantiate a new message it will keep that subject variable in memory as long as the message object itself lives. Now if it did not have the # symbol, once the function it was declared in "went out of scope" aka finished, the variable would be "lost" as the function was complete and the memory was reclaimed by the Ruby VM. There are also "class variables" that are prefaced with two # symbols. This means the variable is shared across all instances of a class.
As for the colon, if it is before a variable that means it is a "symbol", which is usually used as an identifer for hashes and other bits of data in Ruby. If it is at the end of a word that means it is the key portion of a hash identifier in Ruby 1.9+ syntax.
Instance Variables: (#foo = '123') An instance variable is defined and keeps its value throughout the current instance of the request. In the rails mvc paradigm, the most common use of instance variables are used to help communicate data from the controller to the view, and allows you ro define things in one part of the controller and use in another.
class ProjectsController < ApplicationController
before_filter :find_project
def show; end
def update
if #project.update_attributes(params[:project])
...
end
end
private
def find_project
#project = Project.find(params[:id])
end
end
In the above code, you can see that there is a before filter that gets ran before every method. In the above case, we find the current project and save it to an instance variable. And because its an instance method, its able to be access anywhere within this class as well as the views used to render the html.
Local Variables: (foo = '123') Pretty much exactly what the name implies, they are only able to be accessed within the current method (def) of where they are defined.
sometimes have variables with the "#" symbol in front of them, and then some variables do not have the # symbol in front of them.
Variables with the "#" symbol are instance variables,which are not preceded by #,can be constants or local variables or global variables. Read Ruby Programming/Syntax/Variables and Constants.
Sometimes I see variables where the colon is in the front, such as :order
They are called symbols.
and then I see variables where the colon is at the end, such as colon:. I do not understand what the colon is doing.
These probably the Hash syntax(as you give us hints,so I would guess),where keys are symbols. Example : {foo: 1} - this is a Hash.
Also read as you requested :
Normal Variables Vs Instance variable in Ruby, Whats the difference?

How to access an included module's methods from within another included module?

module Foo
attr_accessor :val
end
module Bar
def bar
val = 50
end
end
class FooBar
include Foo
include Bar
end
fb = FooBar.new
puts fb.bar # 50
puts fb.val # nil
I would like to, from within Bar, change Foo's "val" value.
Just so you know, I'm trying to do this because I want to add user authentication through a Facebook Canvas app in Clearance (0.8.2 (old, I know)). The variable that I want to change is https://github.com/thoughtbot/clearance/blob/b8ccca00d91cb336e044b76b5c6ae1d8de9d2d8d/lib/clearance/authentication.rb#L25.
This module gets included into ApplicationController, and I'm including another module afterwards (FacebookAuthenticationHelper) that does something like
def authenticate_facebook
current_user ||= facebook_user if coming_from_facebook?
end
I would love to know if there's a better way to do this as well. I'm not using OAuth, I'm just saving Facebook's user_id sends to my app from signed_request into my DB.
Thanks!
In ruby, any statement of the form varname = value will create a local variable named varname if it doesn't already exist. This is even true within class methods where the class has a setter method of the same name. Furthermore, if a local variable exists, it takes precedence over getters and setters. For example:
class Demo
attr_accessor :foo
def demonstrate!
#foo = 1 #1: Set member variable foo, so we get meaningful output
puts foo #2: Prints 1 (this calls the getter)
puts self.foo #3: Prints 1 (also calls the getter)
foo = 2 #4: Creates a LOCAL variable named foo with the value 2
puts foo #5: Prints 2 (locals take precedence over getters)
puts self.foo #6: Prints 1 (calls the getter - the member variable hasn't changed)
self.foo = 3 #7: Use SELF to ensure you call a getter or setter
puts foo #8: Prints 2 (the local again)
puts self.foo #9: Prints 3 (the member, which is now 3)
end
end
The bad thing about this system is: Look at lines 2 and 5. The same exact code does different things! On line 2, the local variable foo didn't exist yet, so ruby did the "next best" thing and called the getter. But on line 5, the local foo exists, so it takes precedence.
I'd say that this is bad language design: If setters can't be called without self, why should it be okay for getters - especially when it can lead to rickety, context-sensitive code like the above? But it's what we have to work with, and it leads to some general guidelines:
If you can, use #foo. It's obvious what that does.
If you're using a getter or setter, always use self, even when it's not strictly necessary. This makes it obvious what you're calling. It also guarantees your code won't behave differently if you add a local with the same name later.
If you do 1 and 2, you can assume that anything without a # or a self is a local variable (or a function call, but you can probably tell those apart by name).
And that ended up being a bit long-winded, but I was unable to find a good demonstration of the getter/setter/local problem to link to. So maybe this is it - hope it's helpful!

Resources