[Rails] ActiveModel::AttributeMethods まとめ

概要


Rails3から追加された機能で、以下の様なことが実現できる。


なお、ActiveRecord::Baseを継承している場合、`include`, `define_attribute_method`は必要ない。
ActiveRecord::AttributeMethods
ActiveModel::AttributeMethods


class Book < ActiveRecord::Base
attribute_method_suffix '_to_foo'
def attribute_to_foo(attr)
send("#{attr}=", 'foo')
end
end

book = book.new do |o|
o.name_to_foo
o.category_to_foo
end
# => #<Book id: nil, name: "foo", category: "foo", created_at: nil, updated_at: nil>

`attribute_method_suffix '_to_foo'`を記述後、`attribute_to_foo`を定義することで、
全attributeに対して、`name_to_foo`, `category_to_foo`などのようなメソッドが定義できる機能


利用可能な`attribute_method_xxx`


attribute_method_affix


attribute_method_affix prefix: 'foo_', suffix: '_bar'
def foo_attribute_bar(attr)
end

attiribute_method_prefix


attribute_method_prefix 'foo_'
def foo_attribute(attr)
end

attribute_method_suffix


attribute_method_suffix '_foo'
def attribute_foo(attr)
end

`attribute_method_xxx`の引数


attribute_method_suffix '_to_foo'
def attribute_to_foo(attr, *args)
p args
end

alias_attribute


ある属性の別名を定義する
なお、この方法で定義した`attribute`にも`attribute_method_xxx`が適用される。


class Book < ActiveRecord::Base
alias_attribute :foo, :name
end

book = Book.new
book.name = 'foo'
book.foo # => 'foo'

define_proxy_callが黒魔術過ぎた。。。

スポンサーサイト

[Rails4] migrationコマンドまとめ

環境等


ruby-2.0.0p0
rails 4.0.0.beta1

https://github.com/rails/rails/blob/master/guides/source/migrations.md#using-the-reversible-method
を適当にまとめただけの内容


rake db:migrateコマンド


未適用のmigrationファイルをすべて適用させる


rake db:migrate

指定された VERSIONのmigrationファイルを適用させる


rake db:migrate VERSION=[バージョン番号]

バージョン番号はマイグレーションファイルの先頭の日付部分を示す。
(e.g. 20140414101520_create_products なら 20140414101520)


適用させたmigrationファイルを未適用の状態に戻す


rake db:rollback

上記の場合は、1つだけ戻ることに注意。
(e.g. A, B, Cとmigrationが適用された場合は、 Cがrevertされる)
複数ステップ戻す場合は,STEPパラメータを指定する


rake db:rollback STEP=2

上記の場合は、2つ戻る
(e.g. A, B, Cとmigrationが適用された場合は、Cがrevertされ、その後に、Bがrevertされる)


指定されたバージョンのmigrationファイルを適用/未適用する


適用させる場合


rake db:migrate:up VERSION=[バージョン番号]

未適用にする場合(revert)


rake db:migrate:down VERSION=[バージョン番号]

これは、A, B, Cとmigrationが適用された場合において、
Cがrevertできないマイグレーションの場合に、Bをrevertしたい場合等に利用する


migrationファイルの作成


テーブル(モデル)を生成する migrationファイルの作成


`rails g model`を使うのが簡単
XXXには、生成するモデル名(単数形)を指定し、追加したいフィールドをその後ろに フィールド名:型 の形式でつなげていく
なお、foo:string の場合は stringの部分は省略可能


rails g model product name:string price:integer

生成されるマイグレーションファイル


class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.string :name
t.integer :price

t.timestamps
end
end
end

[migrate:upの場合の挙動]
productsというテーブルが生成される。
[migrate:downの場合の挙動]
productsというテーブルが削除される


TIPS


MySQLのENGINEを変更する場合(デフォルトはInnoDB)はoptionsで指定することができる
e.g.) `create_table :products, options: "ENGINE=MEMORY"


フィールドの追加用マイグレーションファイルの作成


AddXXXToYYY という形式。その後、追加するフィールド名:型 をつなげていく
XXX には追加するフィールド名、 YYYにはフィールドを追加するテーブル名を指定する。
なお、`AddFooToProducts`の部分は `add_foo_to_products`でも問題ない。


rails g migration AddFooToProducts foo:string

生成される migrationファイル


class AddFooToProducts < ActiveRecord::Migration
def change
add_column :products, :foo, :string
end
end

[migrate:upの場合の挙動]
productsテーブルにfooというフィールドが生成される。
[migrate:downの場合の挙動]
productsテーブルからfooというフィールドが削除される。


フィールドの削除用マイグレーションファイルの作成


RemoveXXXToYYY という形式。その後、削除するフィールド名:型 をつなげていく
XXX には削除するフィールド名、YYYにはフィールドを削除するテーブル名を指定する。
なお、`RemoveFooFromProducts` の部分は `remove_foo_from_products` でも問題ない。


rails g migration RemoveFooFromProducts foo:string

生成されるマイグレーションファイル


class RemoveFooFromProducts < ActiveRecord::Migration
def change
remove_column :products, :foo, :string
end
end

[migrate:upの場合の挙動]
productsというテーブルから fooというフィールドが削除される。
[migrate:downの場合の挙動]
productsというテーブルにfooというフィールドを生成する。


複数のフィールドの追加/削除のmigrationファイルの作成


同様に AddXXXToYYY, RemoveXXXFromYYYという命名規則で問題ないが、
XXXという部分の命名規則は特に定められていない。
無難に`AddFooAndBarToYYY`などで良いと思われる。


rails g migration add_foo_and_bar_to_products foo:integer bar:integer

生成されるmigrationファイル


class AddFooAndBarToProducts < ActiveRecord::Migration
def change
add_column :products, :foo, :integer
add_column :products, :bar, :integer
end
end

Joinテーブルの作成をするmigrationファイルの作成


書式: `CreateJoinTableXXXYYY XXX YYY`
XXX, YYYには結合するモデル名を指定する。
以下の場合はproductとcategoryのN:Nを結合するテーブルcategories_productsが生成される。


rails g migration create_join_table_product_category product category

生成されるmigrationファイル


class CreateJoinTableProductCategory < ActiveRecord::Migration
def change
create_join_table :products, :categories do |t|
# t.index [:product_id, :category_id]
# t.index [:category_id, :product_id]
end
end
end

複合Indexの部分は、使用するSQLに応じて、コメントアウトを解除すればOK


TIPS


  • Joinテーブルのテーブル名を変更したい場合は、以下のように`table_name`オプションを指定する
    create_join_table :products, :categories, table_name: 'foo'

  • create_join_table中での t.string等は無視される
    create_join_table :products, :categories do |t|
    t.string :foo
    end

  • create_join_tableを利用すると, idフィールド(primary_keyフィールド)は生成されない

migationファイル中で利用可能なメソッド


フィールドの追加


add_column [table名], [フィールド名], [型], [オプション]
e.g.) add_column :products, :foo :string, limit: 32

上記例の場合は、 productsテーブルに fooというフィールドをstringで定義, かつ上限を32文字に制限する
つまりこの場合は foo [varchar(32)]で生成される。


フィールドの削除


remove_column [table名], [フィールド名], [型], [オプション]
e.g.) remove_column :product, :foo, :string, limit: 32

なお、[フィールド名]以降の[型], [オプション]はなくても問題ないが、
ない場合は、revertできないので注意。
revertされるときには、ここで指定された型、オプションでadd_columnされる。


フィールドの変更


フィールドの型の変更を行う場合に利用する
この場合、revertする型等の指定ができないので、`reversible`を利用する
[migrate:up時の挙動]
productsのfooフィールドをinteger型へ変換
[migrate:down時の挙動]
productsのfooフィールドをstring型, limit:32へ変換


def change
reversible do |dir|
dir.up do
change_column :products, :foo, :integer
end

dir.down do
change_column :products, :foo, :string, limit: 32
end
end
end

なお、change_columnで例を示したが、フィールドの変更等は以下のように
change_tableを利用するのが推奨される方法となる。
この場合は、テーブル名の指定が不要。


 change_table :products do |t|
dir.up { t.change :foo, :integer }
dir.down { t.change :foo, :string, limit: 32 }
end

indexの作成/削除


add_index, :products, :foo

remove_index :products, :foo

TIPS


複合INDEXの生成(foo => barの順の場合)


add_index, :products, [:foo, :bar]

INDEX名の変更(INDEX名の長さに制限がある場合など)


add_index, :products, [:foo, :bar], name: 'index_a'

add_timestamps / remove_timestamps


created_at, updated_atを追加/削除するメソッド


add_timestamps :products

remove_timestamps :products

なお、created_atはnot null制約, updated_atはnull許可となる
※MySQL5.6だと、datetimeをnull: falseにすると、自動的にdefault `0000-00-00 00:00:00`となる


フィールド名の変更


fooをbarというフィールド名に変更する例


rename_column :products, :foo, :bar

他にも`remove_reference`, `add_reference`, `rename_table`等がある


オプション色々


index付与


add_column :products, :foo, :integer, index: true

NOT NULL制約


add_column :products, :foo, :integer, null: false

NULL許可


change_column等で NOT NULLをNULL許可にする場合)


change_column :products, :foo, :integer, null: true

デフォルト値


add_column :products, :foo, :integer, default: 100

Helperメソッドで対応出来ない場合


用意されているHelperメソッドで対応出来ない場合は、
`execute`を利用して直接SQLを記述することができる


e.g.) MySQLでパーティション追加用に、idとcreated_atのprimary_keyを設定し、
idをBIGINT, UNSIGNEDに変える例


def change
reversible do |dir|
dir.up do
execute <<-SQL
ALTER TABLE products
DROP PRIMARY KEY,
ADD PRIMARY KEY (id, created_at),
MODIFY id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT;
SQL
end

dir.down do
execute <<-SQL
ALTER TABLE products
MODIFY id INT NOT NULL AUTO_INCREMENT,
DROP PRIMARY KEY,
ADD PRIMARY KEY (id);
SQL
end
end
end

上記を実行すると以下のような構造になる


mysql>show create table products;
CREATE TABLE `products` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`price` int(11) DEFAULT NULL,
`created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`,`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

特定のmigrationをrevertするmigration


例として上記の primary_keyの変更をrevertする場合


require_relative '20130414151754_change_products_primary_key'

class RevertProductsChangePrimaryKey < ActiveRecord::Migration
def change
revert ChangeProductsPrimaryKey
end
end

require_relative で該当のmigrationファイルを指定し、revert Class名をするだけ
ちなみにきちんと、revertのrevertも動作する。

[Rails4] scaffold, jbuilder

Rails4.0 のscaffold変更点


TODO: あとで綺麗にする とりあえず広告を消す


環境


ruby 2.0.0-p0
rails 4.0.0.beta1

サンプル用アプリ


rails new sample

Scaffoldの実行


rails g scaffold author name
rails g scaffold book name author:belongs_to

Migration


rake db:migrate

Railsのサーバ起動


rails s

気づいた変更点


concernsディレクトリが自動生成


ActiveSupport::Concernするやつはここで管理しろよということらしい


binディレクトリがある


./bin/rails -v とかする感じ?


Model.all(params)でDEPRECATION


具体的には、views/books/_form.html.erb を以下のように変更


f.select author_id, Author.all(select: 'id, name').map{|a| [a.name, a.id]}

これはこうしないといけないようだ


f.select author_id, Author.select('id, name').load.map{|a| [a.name, a.id]}

Jbuilderが使用される


views/books/show.json.jbuilderが自動生成される
初期値は以下の様子


json.extract! @book, :name, :author_id, :created_at, :updated_at

例えば、author.nameにしたい場合はこうする感じかな?


json.extract! @book, :name
json.author_name @book.author.try(:name)
json.extract! @book, :created_at, :updated_at

http://localhost:3000/books/1.json にアクセスすると(データは適当に作った)以下のように返ってくる


{"name":"abc","author_name":"あいうえお","created_at":"2013-04-10T15:02:14.417Z","updated_at":"2013-04-10T15:18:11.060Z"}

詳しくはここを参考: jbuilder


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。