#find_byuseful and how is it used?
#wherequery and a
User.find(1)will return an unambiguous object -- it's going to find the user with ID = 1 and give it to you as a Ruby object. But this behavior is actually unusual. Most queries don't actually return a Ruby object, they just fake it. For example:
User.where(id: 1).classand you'll see that it isn't an
Array, it's actually an instance of
ActiveRecord::Relation. Relations are actually just really good at looking like arrays but they've got more going on.
@posts = Post.limit(5), that is really passing your view a relation. It's only when the code in the view actually calls a method on
@posts.first.title) that the query will be run and the relation will get stored as a real Ruby object in memory.
$ rails console) to test them out, because the queries will actually be run right away in the console since it implicitly runs something like the
.inspectmethod on the relation, which requires the query to be run. But try playing with building a query like we did above and checking out its
#class... you'll usually get back
Post.limit(5).order(created_at: :desc)). Because
#limitreturns a Relation,
#ordertakes that relation and adds its own criteria to it. You can chain together a dozen methods this way, and, when it's finally time to execute, ActiveRecord and SQL (if that's what you're using for the DB) will figure out the optimal way to structure the query to achieve the desired result.
#to_aon it to force it to evaluate the query.
ActiveRecord::FinderMethodsdo NOT return
#lastmethods return a single record (a model instance).
#takereturns an array of model instances. Unlike the methods that return
Relationobjects, when called, these will run SQL queries immediately.
#exists?will return true/false.
#any?will be true if any records match the specified criteria and
#many?will be true if multiple records match the specified criteria. You can run each of these either on a model directly, a Relation, an association, or a scope (which we'll cover later). Basically, anywhere you might think of using them, they're likely to work:
?parameters like in normal SQL. When it's not ambiguous (e.g. if you aren't working with multiple tables) you can also choose to specify the table name or not (see #5 below). All of the following are the same:
#find_eachdoes the trick. The basic principle is that it chunks the query into pieces, loading up the first piece and evaluating it before moving onto the next one. This will be helpful for you when optimizing queries but isn't really something to worry too much about up front.
#wherequeries give you a fair bit of flexibility -- they let you specify an exact value to find, a range of values to find, or several values to find. If you know what type of query you're looking for, you can almost guess the proper syntax for executing it.
#findreturns the actual record while
ActiveRecord::Relationwhich basically acts like an array. So if you're using
#whereto find a single record, you still need to remember to go into that "array" and grab the first record, e.g.
User.where(email: "[email protected]")or
User.where(email: "[email protected]").first.
#find_byis a really neat method that basically lets you build your own finder method. It's an alternative to using
#where(to which you'd have to add another method like
#firstto pull the result out of the returned array). If you want to find by a user's email, write
User.find_by(email: '[email protected]').
#selectshould be pretty obvious to a SQL ninja like you -- it lets you choose which columns to select from the table(s), just like in SQL. To select just the ID column for all users, it's as simple as
User.select(:id). You can also use aliases like in SQL but should use quotes instead of symbols, e.g.
@users = User.select("users.id AS user_id")will create a new attribute called
user_id, e.g. allowing you to access
#max. An example (a bit more complex because it involves joining two tables) is if we want to get a count of all the blog posts categorized by each tag. I might write something like:
#havingis sort of like a
#whereclause for grouped queries.
:idcolumn, which table's ID are we asking for? You'll find yourself using more explicit strings when joining, e.g. in the example above (copied below) where we specify the
nameattribute of the
ActiveRecord::Relationthat is returned by a query to execute itself immediately and then you try to run queries on each member of the collection. That's a whole lot of queries and can quickly slow your application down to a snail's pace.
User.all) then loop through each user and call an association it has, like the city the user lives in (
user.city). For this example we're assuming an association exists between User and City, where User
belongs_toa City. This might look like:
user.name... it's because you're reaching through the association with City that we've got to run another full query.
user.citygets treated the same way as
user.name... it doesn't run another query. The trick is the
#includesbasically takes the name of one or more associations that you'd like to load at the same time as your original object and brings them into memory. You can chain it onto other methods like
#pluckmethod, which is covered in the Rails Guide.
#plucklets you skip several steps in the process of pulling up a bunch of records, storing them in memory, then grabbing a specific column and placing it into an array.
#pluckjust gives you the resulting array right away:
#find_by_sqlmethod for this.