Ruby on Rails: How to Set a Variable to a Constant, Where Part of the Name of the Constant Can Change

Ruby on Rails: How do I set a variable to a constant, where part of the name of the constant can change?

Either use:

"User::#{arg2}".constantize

or

User.const_get(arg2)

How to assign variable's value to a constant?

The Ruby constants are expected to preserve the same value, it's a recommendation, not a must:

A Ruby constant is like a variable, except that its value is supposed to remain constant for the duration of the program. The Ruby interpreter does not actually enforce the constancy of constants, but it does issue a warning if a program changes the value of a constant.

In rails, where to put a constant (variable?) that changes based on the current date?

I think that here you can use Rails caching. Look here and here for more details and examples.

Basicaly, you can write to cache:

Rails.cache.write('date', Date.today)

and read:

Rails.cache.read('date')

You can use it in whole Rails application (models, views, controllers, ...).

You can store any object in cache. Default caching uses memory and is availble for single Rails instance, however you can use different cache storing method.

Can `merge!` change a CONST in Ruby?

I have a situation where merge! seems to modify the value of a CONST. Can this occur? How?

No, in general, methods cannot change variable bindings, regardless of whether those variables are local variables, instance variables, class variables, global variables, or constants. Variables aren't objects in Ruby, you can't call methods on them, you can't pass them as arguments to methods, ergo, you can't tell them to change themselves.

The exception to this are meta-programming methods like Binding#local_variable_set, Object#instance_variable_set, Module#class_variable_set, or Module#const_set.

What you can do, however, and what you are doing in this case, is tell the object the variable points to to change itself. The documentation for Hash#merge! is unfortunately a bit unclear in that it does not explicitly mention that Hash#merge! mutates its receiver.

This seems to confirm that, after running the extract_features! method, the FEATURE_DEFAULTS CONST is changed. If I do not use merge! in extract_features!, and use merge instead, then the CONST value does not change.

No, it only confirms that the state of the object FEATURE_DEFAULTS points to changed, it doesn't say anything about whether the binding of FEATURE_DEFAULTS, i.e. which object it points to, changed. You can confirm that the constant still points to the same object by looking at its object_id.

Of course, constants can be re-assigned anyway, albeit triggering a warning.

Ruby on Rails: how do I set a variable where the variable being changed can change?

foo = "bar"
current_user.send("allow_#{foo}=", true)

EDIT:

what you're asking for in the comment is another thing. If you want to grab a constant, you should use for instance

role = "admin"
User.const_get(role)

Using a Variable Name as Attribute in Rails

If you want to assign to an attribute, you need the method name with the equal sign:

f.send("#{percent_field}=", 5)

Also, this:

rank_class = (klass.name).constantize

is equivalent to this:

rank_class = klass

Set a Ruby variable and never be able to change it again?

They are called constants. A constant in Ruby is defined by a UPPER_CASE name.

VARIABLE = "foo"

It is worth to mention that, technically, in Ruby there is no way to prevent a variable to be changed. In fact, if you try to re-assign a value to a constant you will get a warning, not an error.

➜  ~  irb
2.1.5 :001 > VARIABLE = "foo"
=> "foo"
2.1.5 :002 > VARIABLE = "bar"
(irb):2: warning: already initialized constant VARIABLE
(irb):1: warning: previous definition of VARIABLE was here
=> "bar"

It's also worth to note that using constants will warn you if you try to replace the value of the constant, but not if you change the constant value in place.

2.1.5 :001 > VARIABLE = "foo"
=> "foo"
2.1.5 :002 > VARIABLE.upcase!
=> "FOO"
2.1.5 :003 > VARIABLE
=> "FOO"

In order to prevent changes to the value referenced by the constant, you can freeze the value once assigned.

2.1.5 :001 > VARIABLE = "foo".freeze
=> "foo"
2.1.5 :002 > VARIABLE.upcase!
RuntimeError: can't modify frozen String
from (irb):2:in `upcase!'
from (irb):2
from /Users/weppos/.rvm/rubies/ruby-2.1.5/bin/irb:11:in `<main>'
2.1.5 :003 > VARIABLE
=> "foo"

Here's an example inside a class.

class MyClass
MY_CONSTANT = "foo"
end

MyClass::MY_CONSTANT
# => "foo"

Correct use of concern's constants

I just came across the same bug, when trying to implement concerns.

The guide I was following also but the Constant in the included block and seemed to have no error. But my log threw me exactly the same error you have.

After some trial and error, I just removed the Constant from the block and put it outside, like:

module UserInstance
extend ActiveSupport::Concern

included do

end

ACTIVE = 'active'
end

This way I could still access the Constant, but didn't get anymore errors. I'm not 100% sure that this is the right way, but it worked and I couldn't find any errors, so I will go with it.

I would like to now if this works for you too!

Constants and scope in loops with Ruby

There seems to be no strict equivalent to Java's final in ruby. However, you could use remove_const (which is a private method in Module) to get rid of the constant (and the warnings) at the end of the loop:

5.times do |x| 
XPI = x * Math::PI;
puts x;
Object.instance_eval{ remove_const :XPI };
# this would work, too: Object.send(:remove_const, :XPI);
end


Related Topics



Leave a reply



Submit