rails 3 best practice for handling attribute with fixed possibilities - ruby-on-rails

For example if I have an attribute that is limited to a short list of values like:
ways = {:way_1 => 1, :way_2 => 2, :way_3 => 3}
What is the best practice for handling this attribute, for both cases:
User can choose only one value (radio button)
User can choose multiple values (checkbox)
For the first case I would use hash defined in an initializer and save the integer value, for second case I thought of bit manipulation to represent all possible combinations.
Is there a best practice for handling both cases in rails 3?
Edit:
I found this gem BitmaskAttributes which handles the bit manipulation nicely, but I still want to know if this is the best practice?

You can use array and serialize this array in a text attribute in your model
class Expense < ActiveRecord::Base
serialize :ways
# other model code
end
then when saving your model, you can do it like this
Expense.new(:ways => [1, 2])

Related

More efficient, rails way to check for any of three fields being unique?

So, I need check three fields for uniqueness of an object before creating it (from a form), but I will create the object so long as any of the three fields are unique.
My first thought was to just pass the params from the controller to the model, and then run a query to check if a query with those three fields returns > 0 documents. However, I've since learned that this is a dangerous approach, and should not be used.
So I checked the docs, and based off of this snippet
Or even multiple scope parameters. For example, making sure that a teacher can only be on the schedule once per semester for a particular class.
class TeacherSchedule < ActiveRecord::Base
validates_uniqueness_of :teacher_id, scope: [:semester_id, :class_id]
end
I thought I had found my answer, and implemented:
validates_uniqueness_of :link_to_event, :scope => [:name_of_event, :date_of_event]
which works! But, this dataset is going to get very large (not from this form alone, lol), and I'm under the impression that with this implementation, Rails is going to query for all fields with a link_to_event, and then all fields with a name_of_event, and then all fields with a date_of_event. So, my question(s) is:
A) Am I wrong about how rails will implement this? Is it going to be more efficient out of the box?
B) If this will not be efficient for a table with a couple million entries, is there a better (and still railsy) way to do this?
You can define a method that queries the records with all the fields that you want to be unique as a group:
validate :uniqueness_of_teacher_semester_and_class
def uniqueness_of_teacher_semester_and_class
users = self.class.where(teacher_id: teacher_id, semester_id: semester_id, class_id: class_id)
errors.add :base, 'Record not unique.' if users.exists?
end
To answer your questions:
A) Am I wrong about how rails will implement this? Is it going to be more efficient out of the box?
I think Rails will query for a match on all 3 fields, and you should check the Mongo (or Rails) log to see for sure.
B) If this will not be efficient for a table with a couple million entries, is there a better (and still railsy) way to do this?
This is the Rails way. There are 2 things you can do to make it efficient:
You would need indexes on all 3 fields, or a compound index of the 3 fields. The compound index *might* be faster, but you can benchmark to find out.
You can add a new field with the 3 fields concatenated, and an index on it. But this will take up extra space and may not be faster than the compound index.
These days a couple million documents is not that much, but depends on document size and hardware.

Rails 4 querying code convention

Fast Simple Example,
Have a Users table like this,
id : integer
name : varchar(255)
and have some seeds
1, john doe
2, john smith
...
ok, so i'm querying now.
if i want to get the second row with id.
what is the recommended way?
I know there are plenty of rails code convention
User.find(2)
User.find_by(:id => 2)
User.find_by_id(2)
User.where(:id => 2)
and more more...
what is the best recommended way?
our team is using all of the code convention.
I want to choose only one and integrate these codes.
You want a single model or nil:
User.find_by_id(2)
You want a single model or nil, and you might query more later:
User.find_by(:id => 2)
User.find_by(:id => 2, :email => 'user#email.com')
You want a single model or an exception, and you might query more later:
User.find_by!(:id => 2)
User.find_by!(:id => 2, :email => 'user#email.com')
You want a single model or an exception:
User.find(2)
User.find_by_id!(2)
One is short, and one is explicit. Your choice.
You want an ActiveRecord Relation (multiple models) and to chain methods:
User.where(:name => 'Yoda').order('created_on DESC').find(2)
In case lots of Yodas are lurking about.
Sources:
http://guides.rubyonrails.org/active_record_querying.html#dynamic-finders
http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find
http://edgeguides.rubyonrails.org/4_0_release_notes.html#active-record
If id is a primary key, The best way is
User.find(id)
And If id is not a primary one, I recommend you to use
User.find_by_id(id)
Always remember, find returns a single record, whereas where returns all matching records as an array.
It depends entirely on the use case,
The only thing to to note is:
User.find(id)
would raise an Exception if it doesn't find a record, whereas
User.find_by(id: 1)
would simply return nil, If you are handling nil s in your application then you needn't worry about it.
As per deprecation look here.
And also that find() doesnot expect a number, what is expects is that the value you pass must have its 0'th character as number, so
User.find("1-this-works")
will work too.
Ben's answer hits the point - those are not conventions, they are functionally different approaches.
However, some of those expressions are functionally the same - Ruby is designed to allow different ways of expressing the same thing - it is because Ruby is a human-oriented language (Ruby philosophy) which means that it's creator adopted a human-linguistic idea that synonyms enhance our ability to understand the language by provoking helpful associations, when used correctly and don't really hurt when not used correctly (an idea often attributed to the creator of Perl - Larry Wall - see There Is More Than One Way To Do It principle).
Bottom line is - this is one of the basic design principles of the Ruby language - it's generally a good idea to embrace the philosophy of the language that you (assumably?) recently adopted rather than force habits from previous languages onto the new one

Where to define Rails select/radio options and how to store

Where is the best place to define, and how should I store select/radio options for rails (and where to put translations)?
Right now I am defining a Hash within the model and storing the integer keys in the record. I've also placed the translations as 'attributes' within the model translations as it seems to group them together well. ie
PHYSICAL_CONDITIONS = {
1 => "activerecord.attributes.building.condition_excellent",
2 => "activerecord.attributes.building.condition_good",
3 => "activerecord.attributes.building.condition_average_for_age",
4 => "activerecord.attributes.building.condition_fair",
5 => "activerecord.attributes.building.condition_poor"
}.freeze
Is there a better way to do this? I have dozens of fields with options and do not want to create separate tables for each either.
My solution is:
use varchar to store the answer ie 'excellent', 'good' from above. This is actual meaningful data I can see in raw form vs numeric values.
in my model have the options array. The order is maintained and if I re-order them numbers don't matter:
PHYSICAL_CONDITIONS = [
:excellent,
:good
]
under the active record model translation have an options group for each set of options. In the above case I call it :physical_condition_options.
have each translation as a subset of that ie excellent: "Excellent"
If I ever need to convert this to allow multiple selections (checkbox) on the model (happened a number of times), I just remove this subset and make it part of the model. Migration is simpler instead of having to translate numeric values.
have a helper translate those options when passing it to a field
localized_options(Building::PHYSICAL_CONDITIONS,
"activerecord.attributes.building.physical_condition_options.")
This seemed to be the best way to store the data and allow it to be easily translated.

Rails ActiveRecord - Uniqueness and Lookup on Array Attribute

Good morning,
I have a Rails model in which I’m currently serializing an array of information. Two things are important to me:
I want to be able to ensure that this is unique (i.e. can’t have two models with the same array)
I want to be able to search existing models for this hash (in a type of find_or_create_by method).
This model describes a “portfolio” – i.e. a group of stock or bonds. The array is the description of what securities are inside the portfolio, and in what weights. I also have a second model, which is a group of portfolios (lets call it a “Portcollection” to keep things simple). A collection has many portfolios, and a portfolio can be in many collections. In other words:
class Portfolio
serialize :weights
has_and_belongs_to_many :portcollections
class Portcollection
has_and_belongs_to_many :portfolios
When I am generating a “portcollection” I need to build a bunch of portfolios, which I do programmatically (implementation not important). Building a portfolio is an expensive operation, so I’m trying to check for the existence of one first. I thought I could do this via find_or_create_by, but wasn’t having much luck. This is my current solution:
Class Portcollection
before_save :build_portfolios
def build_portfolios
……
proposed_weights = ……
yml =proposed_weights.to_yaml
if port = Portfolio.find_by_weights(yml)
self.portfolios << port
else
self.portfolios << Portfolio.create!(:weights => proposed_weights)
end
……..
end
This does work, but it is quite slow. I have a feeling this is because I’m converting stuff to YAML each time it runs when I try to check for an existing portfolio (this is running probably millions of times), and I’m searching for a string, as opposed to an integer. I do have an index on this column though.
Is there a better way to do this? A few thoughts had crossed my mind:
Calculate an MD5 hash of the “weights” array, and save to a database column. I’ll still have to calculate this hash each time I want to search for an array, but I have a gut feeling this would be easier for the database to index & search?
Work on moving from has_and_belongs_to_many to a has_many => through, and store the array information as database columns. That way I could try to sort out a database query that could check for the uniqueness, without any YAML or serialization…
i.e. something like :
class Portfolio
has_many :portcollections, :through => security_weights
class Portcollections
has_many :portfolios, :through => security_weights
SECURITY_WEIGHTS
id portfolio_id portcollection_id weight_of_GOOG weight_of_APPLE ……
1 14 15 0.4 0.3
In case it is important, the “weights” array would look like this:
[ [‘GOOG’, 0.4] , [‘AAPL’, 0.3] , [‘GE’, 0.3] ]
Any help would be appreciated. Please keep in mind I'm quite an amateur - programming is just a hobby for me! Please excuse me if I'm doing anything really hacky or missing something obvious....
Thanks!
UPDATE 1
I've done some research into the Rails 3.2 "store" method, but that doesn't seem to be the answer either... It just stores objects as JSON, which gives me the same lack of searchability I have now.
I think storing a separate hash in it's own column is the only way to do this efficiently. You are using serialization or a key/value store that is designed to not be easily searchable.
Just make sure you consider sorting on your values before hashing them, other wise you could have the same content but differing hashes.

Sort by state in database

Given I have a model house and it lives through several states, something like this:
Dreaming —> Planning —> Building —> Living —> Tearing down
If I would want to retrieve let's say ten houses from the databse and order them by the state field, I'd get first all houses in the Building state, then Dreaming, then Living, …
Is it possible to fetch all houses from the database and order them by the state in the order intended before retrieving them? Meaning, first all houses in the Dreaming state, then Planning, etc. E.g. by providing the order in an array for comparison of sorts.
I'd like to avoid doing this in Ruby after having fetched all entries as well as I wouldn't want to use IDs for the states.
After reading up on enum implementations, I guess, if I can make it work, I'll try to combine the enum column plugin with the state_machine plugin to achieve what I'm after. If anyone has done something like this before (especially the combination under Rails 3), I'd be grateful for input!
Here's some information on how to use SQL ENUMs in rails -- they're relatively database portable and do roughly what you want -- http://www.snowgiraffe.com/tech/311/enumeration-columns-with-rails/
If you are using MySQL, then the solution is to do ORDER BY FIELD(state, 'Building', 'Dreaming', 'Living', ...):
House.order("FIELD(state, 'Building', 'Dreaming', 'Living', ...)")
If you want to order the collection after a certain criteria then you must store that criteria somewhere.
I don't know if this goes against your "not in Ruby" criteria but I would probably do something like this:
class House < ActiveRecord::Base
STATES { 0 => "Dreaming",
1 => "Planning",
2 => "Building",
3 => "Living",
4 => "Tearing Down" }
validates_inclusion_of :state, :in => STATES.keys
def state_name
STATES[self.state]
end
end
#houses = House.order("state")
In this case the db field state is an integer instead of a string. It makes it very effective for database storage as well as querying.
Then in your view, you call state_name to get the correct name from the STATES hash stored in the model. This can also be changed to use i18n localization by using labels instead of strings in the hash.

Resources