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
Related
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.
I have a model which has many of another model but this model only needs to have 10 or less id's in it.
Let's say it has, Bathroom, Kitchen, LivingRoom for arguments sake and the new records will probably never need to change.
What is the best way of making a model like this that doesn't use a database table?
This may not be best practices, but to solve the same problem I just specified a collection in my model, like this:
ROOM_TYPES = [ "Bathroom", "Living Room", "Kitchen" ]
Then in the view:
<%= f.select(:room_type, Project::ROOM_TYPES, {:prompt => '...'}) %>
(replace Project with your actual model name.)
Super-straightforward, almost no setup. I can see how it would be difficult to maintain though, since there's no way to add items without accessing the Rails code, but it does get the job done quickly.
Even though the collection of rows never changes, it's still useful to have this as a table in your database in order to leverage ActiveRecord relations. A less contrived example would be a database table that has a list of US states. This is highly unlikely to change, and would likely have only a couple of columns (state name and state abbreviation). However, by storing these in the database and supporting them with ActiveRecord, you preserve the ability to do handy things like searching for all users in a state using conventional rails semantics.
That being said, an alternative would be to simply create a class that you stick in your models directory that does not inherit from ActiveRecord, and then either populate it once from the database when the application loads, or simply populate it by hand.
A similar question was asked yesterday, and one of the answers proposes a mechanism for supporting something similar to what you want to do:
How to create a static class that represents what is in the database?
I have an ActiveRecord model Language, with columns id and short_code (there are other columns, but they are not relevant to this question). I want to create a method that will be given a list of short codes, and return a list of IDs. I do not care about associations, I just need to end up with an array that looks like [1, 2, 3, ...].
My first thought was to do something like
def get_ids_from_short_codes(*short_codes)
Language.find_all_by_short_code(short_codes.flatten, :select => 'id').map(&:id)
end
but I'm not sure if that's needlessly wasting time/memory/processing.
My question is twofold:
Is there a way to run an ActiveRecord find that will just return an array of a certain table column rather than instantiating objects?
If so, would it actually be worthwhile to collect an array of length n rather than instantiating n ActiveRecord objects?
Note that for my specific purpose, n would be approximately 200.
In Rails 3.x, you can use the pluck method which returns the values from the requested field without instantiating objects to hold them.
This would give you an array of IDs:
Language.where(short_code: short_codes.flatten).pluck(:id)
I should mention that in Rails 3.x you can pluck only one column at a time but in Rails 4 you can pass multiple columns to pluck.
By the way, here's a similar answer to a similar question
Honestly, for 200 records, I wouldn't worry about it. When you get to 2000, 20,000, or 200,000 records - then you can worry about optimization.
Make sure you have short_code indexed in your table.
If you are still concerned about performance, take a look at the development.log and see what the database numbers are for that particular call. You can adjust the query and see how it affects performance in the log. This should give you a rough estimate of performance.
Agree with the previous answer, but if you absolutely must, you can try this
sql = Language.send(:construct_finder_sql, :select => 'id', :conditions => ["short_code in (?)", short_codes])
Language.connection.select_values(sql)
A bit ugly as it is, but it doesn't create in-memory objects.
if you're using associations you can get raw ids directly from ActiveRecord.
eg.:
class User < ActiveRecord::Base
has_many :users
end
irb:=> User.find(:first).user_ids
irb:>> [1,2,3,4,5]
Phil is right about this, but if you do find that this is an issue. You can send a raw SQL query to the database and work at a level below ActiveRecord. This can be useful for situations like this.
ActiveRecord::Base.connection.execute("SQL CODE!")
Benchmark your code first before you resort to this.
This really is a matter of choice.
Overkill or not, ActiveRecord is supposed to give you objects since it's an ORM. And Like Ben said, if you do not want objects, use raw SQL.
I have a little example Rails app called tickets, which views and edits fictional tickets sold to various customers. In tickets_controller.rb, inside def index, I have this standard line, generated by scaffolding:
#tickets = Ticket.find(:all)
To sort the tickets by name, I have found two possible approaches. You can do it this way:
#tickets = Ticket.find(:all, :order => 'name')
... or this way:
#tickets = Ticket.find(:all).sort!{|t1,t2|t1.name <=> t2.name}
(Tip: Ruby documentation explains that sort! will modify the array that it is sorting, as opposed to sort alone, which returns the sorted array but leaves the original unchanged).
What strategy do you normally use? When might you use .sort! versus the :order => 'criteria' syntax?
Use :order => 'criteria' for anything simple that can be done by the database (ie. basic alphabetical or chronological order). Chances are it's a lot faster than letting your Ruby code do it, assuming you have the right indexes in place.
The only time I could think you should use the sort method is if you have a complex attribute that's calculated at run-time and not stored in the database, like a 'trustworthiness value' based off number of good/bad responses or something. In that case it's better to use the sort method, but be aware that this will screw things up if you have pagination in place (each page will have ITS results in order, but the set of pages as a whole will be out of order).
I specify an order in the ActiveRecord finder or in the model association because sorting using SQL is faster. You should take advantage of the features offered by the RDBMS when you're able to do so.
User model has three keys: is_master, is_standard, is_guest because I originally wanted to use activerecord's boolean methods like is_master? or is_power?.
However, if it would be better to create a UserType relationship and create my own methods like this:
def master?
return true if self.user_type = 1
end
If the master/standard/guest relationship is mutually exclusive (that is, you can only ever be one of them) then a field that stores the type (in a human-readable form, please -- no opaque numbers) is better. You can always reimplement is_foo? trivially.
On the other hand, if you could have an account that be more than one of master/standard/guest/whatever at once, then stick with the separate boolean fields.
As a DBA I always hate when people are using columns as flags, it would be a lot of extra columns.
If it is all the same type (like account type), I would do as the first anwer suggests (including using text, not numbers).
If you on the other hand needs it for separate flags or multiple types (but having a restricted number) I would actually go for a binary calculation.
That is, have one columns in the table representing all the flags and then assign each flag a number.
ex.
FLAGS = {:master => 1, :standard => 2, :guest => 4, :power => 8,
:another_flag => 32, :yet_another_flag => 64}
def is_master?
self.flags & FLAGS[:master]
end
def is_standard?
self.flags & FLAGS[:standard]
end
It requires a bit more work when setting the values, but doesn't clutter up the table with a lot of columns used only for flags.
If you look at how the restful authentication plugin does it (which includes user roles) they use a join table.
I think a join is much more readable.Using a join allows you to be more flexible with your role-system.
If you require that a user can only have a single role I would put that logic in your model.
I'd start with the simplest thing that solves your current need. Refactor and add complexity from there as needed. Sounds like a set of boolean columns is just what you need.