How does Rails deal with method-name-unfriendly enum values? - ruby-on-rails

I have a (Rails) class that has the following enum value:
class DeploymentRequest
enum frequency: ['One-off', 'Monthly', 'Quarterly', 'Annual']
#...
end
As per the docs (although slightly to my surprise, case-sensitively), a DeploymentRequest has such instance methods as #Monthly?, #Monthly!, #Quarterly? and so on (and the class method .Monthly). But the 'One-off' value is throwing it and/or me. I've tried
dr.One_off?
dr.Oneoff?
dr.oneoff? # (one lives in hope)
But none work (and Pry/IRB aren't suggesting any helpful alternatives). What's happening here? Has Rails just not defined any such set of methods, or has it named them something I haven't found?

Rails converts these enums into symbols. You'll be able to see some of these methods by looking at the difference in instance methods between your model and ActiveRecord::Base (assuming that's what you're using):
DeploymentRequest.instance_methods - ActiveRecord::Base.instance_methods
> [:Quarterly?, :Quarterly!, :Annual?, :Annual!, :"One-off?", :"One-off!", :Monthly?, :Monthly!, ....
You can see that the method you need is ":One-off?", which is hard to call. But you can use send:
dr.send(:"One-off?")
Ugly, but without changing the enum value might be your only option.

This is a pretty gross misuse of ActiveRecord::Enum. Its not intended to store the human friendly strings you want to use on the frontend. Rather its meant to be used to map a set of integers in the database to named states in the model. If the mapping does not follow the Ruby conventions for method naming you're doing it wrong.
If you want to display the mappings of an enum on the frontend you should use the I18n module or some other kind of mapping that maps the enum keys to the human readable version:
en:
deployment_request:
frequencies:
one_off: 'One-off'
monthly: 'Monthly'
quarterly: 'Quarterly'
annual: 'Annual'
I18n.t :"deployment_request.frequencies.#{deployment_request.frequency}"

Related

How to deal with Money in Rails and Mongoid

I know this question has been asked before, but most answers I've found are related to ActiveRecord or old (most cases, both) and I was wondering whether there's a new take on this.
Is short, my Rails app is an API, so please keep this in mind (can't normally use lots of helpful little view related helpers).
I've been reading about this and found the MoneyRails which seems quite neat. The problem I'm having with it is that when I retrieve the data, it returns an object instead of the an usable value:
class MyModel
include Mongoid::Document
...
field :price_GBP, type: Money
...
end
So to create the document I send a number and it created the document fine. Now when I query the same document it returns an object for price_GBP, which is fine, but my main grip is that it return the value fractional as in my_obj.price_GBP[:fractional] as a string rather than a number.
I'd rather not have my client to have to do the conversion fro string to number than to decimal.
I guess I could create a little helper that would convert the value in such circumstances like so (in my Model):
def my_helper
self.price_GBP = BigDecimal(self.price_GBP) # or something along those lines
end
Then in my controller:
#my_model = Model.find(id)
#my_model.price_GBP = #my_model.price_GBP = #my_model.my_helper
render json: #my_model
With the above in mind, would this be the best approach? If yes, what's the point of using the MoneyRails gem then?
Secondly, if not using the MoneyRails gem, should I use BigDecimal or Float as the field type?
When I tried BigDecimal, the data was saved ok, but when I've retrieve it, I got an string rather than a number. Is this the correct behaviour?
When I tried Float it all worked fine, but I read somewhere that Float is not the most accurate.
What are your thoughts?
Avoid using Float if you're planning on performing any type of arithmetic on the currency values. BigDecimal is good or you can also represent the value in cents and store it as an Integer. This is actually how the Money gem works.
My recommendation would be to continue to use the MoneyRails gem and use the built-in helpers to output the values. You mentioned not being able to use the helpers but I don't see what's preventing that - Rails includes jbuilder which allows you to formulate your JSON structure in a view with access to all "helpful little view related helpers" - for example
# app/views/someresource/show.json.jbuilder
# ...other attributes
json.price_GBP = humanized_money(#my_model.price_GBP)

Rails 3.2 - What is the name of a variable declared in model (Model::VARIABLE) and is there a better practice?

In my app I have been using the following pattern to store data that is used in a signup form:
class MyModel
...
LOCATIONS = { "Virginia" => "[Richmond, Virginia Beach]",
"Georgia" => "[Atlanta, Savannah]" }
end
# form
= f.select :location, Worker::LOCATIONS
My questions are: 1) is there a name for this Worker::LOCATIONS variable and 2) is there a better practice? Some of my select fields have quite a bit of data and my my_model.rb field is getting pretty long because of it.
They're just called constants in ruby. It's perfectly fine to use constants but in this case you're putting a lot of view related code in your models which is bad practice.
I would suggest you look at using presenters, which are a separate type of object from models and are used specifically for storing view related code. Alternatively you could just put that stuff in a helper (this is fine for smaller projects).
Hope this helps.

Is there any built-in way to automatically enforce a type/class on an instance variable in Ruby?

I'm working with Ruby and Rails, so any Rails extension of Ruby should be fine too.
I'm wondering if there's a way to effectively force a type on instance variables (rather, their setters and getters) that's easier than manually defining them.
The class method attr_accessor and the like don't enforce a type. I noticed for instance that Rails' ActiveRecord::Base class does automatic casting on setters. It knows from the database that a particular active record variable is an integer, and setting it with #record.integer_variable = '1' automatically casts the argument and allows further access through #record.integer_variable # => 1.
Is there a way to tap into this?
I could write my own getters and setters as class methods, but if smarter folk have already done the heavy lifting, I'd rather not have to trust myself.
I don't know if there's already something about it, but you can solve this problem with just a few lines of meta-programming:
module EnforceTypes
def attr_accessor_of_type(name, type)
send :define_method, name do
instance_variable_get("##{name}")
end
send :define_method, "#{name}=" do |v|
raise ArgumentException unless v.is_a? type
instance_variable_set("##{name}", v)
end
end
end
Usage:
class MyClass
extend EnforceTypes
attr_accessor_of_type :some_string, String
end
Of course you can make it a little smart by changing the 2nd emitted method, performing some conversions, etc.
Here's a nice reference: http://www.raulparolari.com/Ruby2/attr_accessor
And remember, almost anything that you can do by manually copy-and-pasting lots of code, can be solved with meta-programming.

Ruby on Rails- :symbols, #iVars and "strings" - oh my!

New to Rails and trying to get my head around when/why to use :symbols, #ivars , "strings" within the framework.
I think I understand the differences between them conceptually
only one :symbol instance per project
one #ivar per instance
multiple "strings" - as they are created whenever referenced (?)
Feel free to correct me!
The main confusion comes from understanding the rules & conventions of what Rails expects - where and WHY?
I'm sure there's an "Ah ha!" moment coming but I haven't had it yet...as it seems pretty arbitrary to me (coming from C/Obj-C).
-thx
The #instance_variable is an instance variable. It is usually defined in the controller and accessible in the views.
The "string" is a string, like as in any other language.
The :symbol, is as you mentioned it's an efficient way of representing names and strings; they are literal values. It is initialized and exists only once during the ruby session. It's not a string, since you don't have access to String methods; it's a Symbol. On top of that, it's immutable. For those reasons, it becomes very handy in representing keys in hashs. Rails methods uses hashes, thus, you find symbols a bit everywhere in Rails.
Instance variables are pretty straightforward: they track properties/values of a particular instance, so you use them when you the values will vary across instances.
Symbols vs. strings are a bit more arbitrary. Symbols are generally used for constant values, in much the same way that a language such as C would use enums; Ruby doesn't have enums, so symbols are often used to fill that gap. Strings are used for more varied pieces of text that won't be used as a flag or similar constant.
Symbols are kind of like pointers (not in the C-ish way, but in C-ish thinking, they point). Well, you use symbols when you are manipulating properties. They are one of the great benefits of dynamic typing if you'd ask me. (For potential voters I do not mean any harm, I do know that they are not pointers, but it felt 'ah-ha!' for me).
:action => "index"
Instance variables are needed when you fetch data from your model and you want to use them across your views (inside your controller method).
def my_controller_method
#myposts = Post.find(:all)
end
# inside view
<% for #myposts do |m| %>
<i><%= m.title %></i>
<% end %>
Just a heads up, the rules and conventions kinda change rapidly (as I discovered on my Rails journey) quite a lot per version. Having the right guide with the right Rails helps. Good luck with coding!
Instance variables don't really belong in the same list as strings and symbols. Strings and Symbols are types of classes whereas instance variables are a type of variable. So instance variables (#var) are just a way to store a value between methods of one instance of one class:
class Calculator
#counter = 0
def inc
#counter += 1
end
def dec
#counter -= 1
end
end
Here is a good article on the distinction between symbols and strings.
The Rails controller access the rails database through Models by ORM (Object Relation Mapping)i.e Model class will mapped to its corresponding table and Objects are directly mapped to rows in the table.In order to get the results for a given user query,the instance variable (#instance_variable) is the perfect choice to deal with it.

When you say Ruby is reflective, does this mainly refer to "duck typing"?

I was reading a text describing Ruby and it said the following:
Ruby is considered a “reflective”
language because it’s possible for a
Ruby program to analyze itself (in
terms of its make-up), make
adjustments to the way it works, and
even overwrite its own code with other
code.
I'm confused by this term 'reflective' - is this mainly talking about the way Ruby can look at a variable and figure out whether it's an Integer or a String (duck typing), e.g.:
x = 3
x = "three" # Ruby reassigns x to a String type
To say Ruby is "reflective" means that you can, for instance, find out at runtime what methods a class has:
>> Array.methods
=> ["inspect", "private_class_method", "const_missing",
[ ... and many more ... ]
(You can do the same thing with an object of the class.)
Or you can find out what class a given object is...
>> arr = Array.new
=> []
>> arr.class
=> Array
And find out what it is within the class hierarchy...
>> arr.kind_of?
>> arr.kind_of? Array
=> true
>> arr.kind_of? String
=> false
In the quote where they say "it’s possible for a Ruby program to analyze itself" that's what they're talking about.
Other languages such as Java do that too, but with Ruby it's easier, more convenient, and more of an everyday part of using the language. Hence, Ruby is "reflective."
No, it means that you can issue a ruby command to get information about, well, just about anything. For example, you can type the command File.methods() to get a listing of all methods belonging to the File module. You can do similar things with classes and objects -- listing methods, variables, etc.
Class reopening is a good example of this. Here's a simple example:
class Integer
def moxy
if self.zero?
self - 2
elsif self.nonzero?
self + 2
end
end
end
puts 10.moxy
By reopening a standard Ruby class - Integer - and defining a new method within it called 'moxy', we can perform a newly defined operation directly on a number. In this case, I've defined this made up 'moxy' method to subtract 2 from the Integer if it's zero and add two if it's nonzero. This makes the moxy method available to all objects of class Integer in Ruby. (Here we use the 'self' keyword to get the content of the integer object).
As you can see, it's a very powerful feature of Ruby.
EDIT: Some commenters have questioned whether this is really reflection. In the English language the word reflection refers to looking in on your own thoughts. And that's certainly an important aspect of reflection in programming also - using Ruby methods like is_a, kind_of, instance_of to perform runtime self-inspection. But reflection also refers to the the ability of a program to modify its own behavior at runtime. Reopening classes is one of the key examples of this. It's also called monkey patching. It's not without its risks but all I am doing is describing it here in the context of reflection, of which it is an example.
It refers mainly at how easy is to inspect and modify internal representations during run-time in Ruby programs, such as classes, constants, methods and so on.
Most modern languages offer some kind of reflective capabilities (even statically typed ones such as Java), but in Ruby, it is so easy and natural to use these capabilities, that it really make a real difference when you need them.
It just makes meta-programming, for example, an almost trivial task, which is not true at all in other languages, even dynamic ones.

Resources