replace Replaces a collection with an array of new items and diffs just the new stuff. @post = Post.find(params[:id]) new_tags = params[:tags].split(",").map(&:strip).map do |tag_name| Tag.find_or_initialize_by(name: tag_name) end @post.tags.replace(new_tags) @post.tags.replace(["doo", "ggie", "gaga"]) # => ActiveRecord::AssociationTypeMismatch: Tag expected, got String
More than first and last @post.tags.second @post.tags.second_to_last @post.tags.third @post.tags.third_to_last @post.tags.fourth @post.tags.fifth @post.tags.forty_two
Not the whole thing Several methods to limit the returned attributes: Post.all.select(:id) # SELECT "posts"."id" FROM "posts" # => #]> Post.all.pluck(:id) # SELECT "posts"."id" FROM "posts" # => [1] Post.all.ids # SELECT "posts"."id" FROM "posts" # => [1]
Maths AR methods that do math in the database Book.average(:price) # SELECT AVG("books"."price") FROM "books" Book.minimum(:price) # SELECT MIN("books"."price") FROM "books" Book.maximum(:price) # SELECT MAX("books"."price") FROM "books" Book.sum(:price) # SELECT SUM("books"."price") FROM "books"
Group and having Adding conditions to your groupings. Post.group(:word_count).having("created_at > ?", 1.years.ago) # Posts grouped by their word_count if they were created in the last year
New in Rails 5: or Generate an OR SQL query. Works great with scope class Post < ApplicationRecord scope :featured, -> { where(featured: true) } scope :recent, -> { where("created_at > ?", 2.days.ago) } end Post.featured.or(Post.recent) # SELECT "posts".* FROM "posts" # WHERE ("posts"."featured" = ? # OR (created_at > '2016-08-08 17:07:58.750856')) [["featured", true]]
Arel predicates Who wants to write SQL? Not this guy. Arel is the code that powers ActiveRecord's queries, and we can use it to write Ruby instead of SQL fragments.
class Post < ApplicationRecord # Helper method to make things a bit easier def self.[](name) self.arel_table[name] end end Post.where(Post[:created_at].gt 2.days.ago) # Same as : Post.where(Post.arel_table[:created_at].gt 2.days.ago) # Same as: Post.where('created_at > ?', 2.days.ago) # SELECT "posts".* FROM "posts" WHERE ("posts"."created_at" > '2016-08-08 17:38:46.068891')