Active Record

Active Record Basics — Ruby on Rails Guides
ActiveRecord::Relation
ActiveRecord::Transactions::ClassMethods
Active Record Associations — Ruby on Rails Guides

through

ActiveRecord::Associations::ClassMethods

:through Specifies an association through which to perform the query. This can be any other type of association, including other :through associations. Options for :class_name, :primary_key and :foreign_key are ignored, as the association uses the source reflection.

If the association on the join model is a belongs_to, the collection can be modified and the records on the :through model will be automatically created and removed as appropriate. Otherwise, the collection is read-only, so you should manipulate the :through association directly.

If you are going to modify the association (rather than just read from it), then it is a good idea to set the :inverse_of option on the source association on the join model. This allows associated records to be built which will automatically create the appropriate join model records when they are saved. (See the 'Association Join Models' section above.)

:source Specifies the source association name used by has_one :through queries. Only use it if the name cannot be inferred from the association. has_one :favorite, through: :favorites will look for a :favorite on Favorite, unless a :source is given.

:source_type Specifies type of the source association used by has_one :through queries where the source association is a polymorphic belongs_to.

Choosing which way to build a many-to-many relationship is not always simple. If you need to work with the relationship model as its own entity, use has_many :through. Use has_and_belongs_to_many when working with legacy schemas or when you never work directly with the relationship itself.

Has Many associations can be configured with the :through option to use an explicit join model to retrieve the data. This operates similarly to a has_and_belongs_to_many association. The advantage is that you're able to add validations, callbacks, and extra attributes on the join model.

An important caveat with going through has_one or has_many associations on the join model is that these associations are read-only.

If you are using a belongs_to on the join model, it is a good idea to set the :inverse_of option on the belongs_to, which will mean that the following example works correctly (where tags is a has_many :through association):

@post = Post.first @tag = @post.tags.build name: "ruby" @tag.save The last line ought to save the through record (a Taggable). This will only work if the :inverse_of is set

You can actually specify any association with the :through option, including an association which has a :through option itself

There are limitations to :inverse_of support: does not work with :through associations

has_many :through, where the default strategy is delete_all (delete the join records, without running their callbacks).

:dependent:If using with the :through option, the association on the join model must be a belongs_to, and the records which get deleted are the join records, rather than the associated records.

:inverse_of:Does not work in combination with :through or :as options.

inverse_of

ActiveRecord::Associations::ClassMethods

:inverse_of Specifies the name of the has_one or has_many association on the associated object that is the inverse of this belongs_to association. Does not work in combination with the :polymorphic options. See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.

:inverse_of Specifies the name of the belongs_to association on the associated object that is the inverse of this has_many association. Does not work in combination with :through or :as options. See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.

You can use :inverse_of to avoid an extra query during validation.

If you are going to modify the association (rather than just read from it), then it is a good idea to set the :inverse_of option on the source association on the join model. This allows associated records to be built which will automatically create the appropriate join model records when they are saved. (See the 'Association Join Models' section above.)

You can use :inverse_of to avoid an extra query during validation.(:require)

polymorphic

Active Record Associations — Ruby on Rails Guides

With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a picture model that belongs to either an employee model or a product model.

If you have an instance of the Picture model, you can get to its parent via @picture.imageable. To make this work, you need to declare both a foreign key column and a type column in the model that declares the polymorphic interface:

f:id:keiwt:20150905204303p:plain

They do not work with :inverse_of associations.

serialize

ActiveRecord::AttributeMethods::Serialization::ClassMethods

If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, then specify the name of that attribute using this method and it will be handled automatically. The serialization is done through YAML. If class_name is specified, the serialized object must be of that class on assignment and retrieval. Otherwise SerializationTypeMismatch will be raised.

# Serialize a preferences attribute.
class User < ActiveRecord::Base
  serialize :preferences
end

# Serialize preferences using JSON as coder.
class User < ActiveRecord::Base
  serialize :preferences, JSON
end

# Serialize preferences as Hash using YAML coder.
class User < ActiveRecord::Base
  serialize :preferences, Hash
end

accepts_nested_attributes_for

ActiveRecord::NestedAttributes::ClassMethods

1画面で複数モデルを同時に触る場合に使用します。

accepts_nested_attributes_forよりはcocoon or virus gemを使用することを推奨します。

accepts_nested_attributes_forを使用すると、関連するモデルに関する処理がDRYではなくなってしまいます。

Nested attributes allow you to save attributes on associated records through the parent.
By default nested attribute updating is turned off and you can enable it using the #accepts_nested_attributes_for class method.
When you enable nested attributes an attribute writer is defined on the model.

The attribute writer is named after the association, which means that in the following example, two new methods are added to your model:

author_attributes=(attributes) and pages_attributes=(attributes).

Note that the :autosave option is automatically enabled on every association that #accepts_nested_attributes_for is used for.

Now, when you add the _destroy key to the attributes hash, with a value that evaluates to true, you will destroy the associated model:

Note that the model will not be destroyed until the parent is saved.

class Member < ActiveRecord::Base
  has_one :avatar
  accepts_nested_attributes_for :avatar, allow_destroy: true
end

params = { member: { name: 'Jack', avatar_attributes: { icon: 'smiling' } } }
member = Member.create(params[:member])

member.avatar_attributes = { id: '2', _destroy: '1' }
member.avatar.marked_for_destruction? # => true
member.save

class Member < ActiveRecord::Base
  has_many :posts
  accepts_nested_attributes_for :posts, reject_if: :reject_posts

  def reject_posts(attributed)
    attributed['title'].blank?
  end
end

enum

ActiveRecord::Enum

Declare an enum attribute where the values map to integers in the database, but can be queried by name. Example:

class Conversation < ActiveRecord::Base
  enum status: [ :active, :archived ]
end

# conversation.update! status: 0
conversation.active!
conversation.active? # => true
conversation.status  # => "active"

# conversation.update! status: 1
conversation.archived!
conversation.archived? # => true
conversation.status    # => "archived"

You can use the :prefix or :suffix options when you need to define multiple enums with same values. If the passed value is true, the methods are prefixed/suffixed with the name of the enum. It is also possible to supply a custom value:

class Conversation < ActiveRecord::Base
  enum status: [:active, :archived], _suffix: true
  enum comments_status: [:active, :inactive], _prefix: :comments
end

conversation.active_status!
conversation.archived_status? # => false

conversation.comments_inactive!
conversation.comments_active? # => false

scope

Active Record Validations — Ruby on Rails Guides

There is a :scope option that you can use to specify other attributes that are used to limit the uniqueness check:

class Holiday < ActiveRecord::Base
  validates :name, uniqueness: { scope: :year,
    message: "should happen once per year" }
end

※特定の休日は年に1回しかない
※uniquenessはデータベースの制約は作成しないので、複数の接続でも一意性制約を担保するためには複合一意インデックスを作成する必要がある

Active Record Query Interface — Ruby on Rails Guides

Scoping allows you to specify commonly-used queries which can be referenced as method calls on the association objects or models. With these scopes, you can use every method previously covered such as where, joins and includes. All scope methods will return an ActiveRecord::Relation object which will allow for further methods (such as other scopes) to be called on it.

class Article < ActiveRecord::Base
  default_scope { where("removed_at IS NULL") }
  scope :active, -> { where state: 'active' }
  scope :inactive, -> { where state: 'inactive' }
  scope :published,               -> { where(published: true) }
  scope :published_and_commented, -> { published.where("comments_count > 0") }
  scope :created_before, ->(time) { where("created_at < ?", time)
end

enumとしてstatusを定義すればwhere句でstatusを見るscopeは不要です ※コールバックの際にはscopeを使えば、より可読性が上がり、DRYになります。

Article.published # => [published articles]
Article.created_before(Time.zone.now)
User.active.inactive # SELECT "users".* FROM "users" WHERE "users"."state" = 'active' AND "users"."state" = 'inactive'
Client.unscoped.load

mount_uploader

github.com

rails g uploader Avatar

app/uploaders/avatar_uploader.rb

class AvatarUploader < CarrierWave::Uploader::Base
  storage :file

  def extension_white_list
    %w(jpg jpeg gif png)
  end
end

uploader = AvatarUploader.new
uploader.store!(my_file)
uploader.retrieve_from_store!('my_file.png')

rails g migration add_avatar_to_users avatar:string

class User < ActiveRecord::Base
  mount_uploader :avatar, AvatarUploader
end

u = User.new
u.avatar = params[:file] # Assign a file like this, or

# like this
File.open('somewhere') do |f|
  u.avatar = f
end

u.save!
u.avatar.url # => '/url/to/file.png'
u.avatar.current_path # => 'path/to/file.png'
u.avatar_identifier # => 'file.png'

Active Record Validations Overview

  • バリデーションが呼び出されるもの
create
create!
save
save!
update
update!
  • バリデーションが呼び出されないもの
decrement!
decrement_counter
increment!
increment_counter
toggle!
touch
update_all
update_attribute
update_column
update_columns
update_counters
  • バリデーションエラーの内容を取得
@hoge.errors.messages

The :on option lets you specify when the validation should happen.

The default behavior for all the built-in validation helpers is to be run on save (both when you're creating a new record and when you're updating it).

If you want to change it, you can use on: :create to run the validation only when a new record is created or on: :update to run the validation only when a record is updated.

Active Record Validations Helpers

validates :terms_of_service, acceptance: true

has_many :books
validates_associated :books

validates :email, confirmation: true
validates :email_confirmation, presence: true

validates :subdomain, exclusion: { in: %w(www us ca jp), message: "%{value} is reserved." }
validates :size, inclusion: { in: %w(small medium large), message: "%{value} is not a valid size" }

validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/, message: "only allows letters" }

validates :name, length: { minimum: 2 }
validates :bio, length: { maximum: 500 }
validates :password, length: { in: 6..20 }
validates :registration_number, length: { is: 6 }

validates :content, length: {
  minimum: 300,
  maximum: 400,
  tokenizer: lambda { |str| str.split(/\s+/) },
  too_short: "must have at least %{count} words",
  too_long: "must have at most %{count} words"
}

validates :games_played, numericality: { only_integer: true }
※/\A[+-]?\d+\Z/
※Note that the regular expression above allows a trailing newline character.

has_many :line_items, inverse_of: :order
※アソシエーションの存在のバリデーション

validates :boolean_field_name, presence: true
validates :boolean_field_name, inclusion: { in: [true, false] }
validates :boolean_field_name, exclusion: { in: [nil] }

validates :name, :login, :email, absence: true
※presenceだと、ホワイトスペースを許容してしまうので

validates :email, uniqueness: true
※case_sensitiveはデフォルトtrue
※これだけだと、2つのコネクションで同じemailができてしまう  
※emailにindexを付けないと一意性は担保されない

validates :name, uniqueness: { scope: :year, message: "should happen once per year" }

Common Validation Options

validates :size, inclusion: { in: %w(small medium large), message: "%{value} is not a valid size" }, allow_nil: true
validates :title, length: { is: 5 }, allow_blank: true

validates :email, uniqueness: true, on: :create
validates :age, numericality: true, on: :update

Conditional Validation

class Order < ActiveRecord::Base
  validates :card_number, presence: true, if: :paid_with_card?
 
  def paid_with_card?
    payment_type == "card"
  end
end
Remove all ads