Railsのhas_oneのsaveに注意!
has_one(1:1)のアソシエーションの場合
autosave: true
を付けないと、アソシエーション先authorのnameを変更してpostをsaveしても、authorはsaveされない
class Post has_one :author, autosave: true end
post = Post.find(1) post.title # => "The current global position of migrating ducks" post.author.name # => "alloy" post.title = "On the migration of ducks" post.author.name = "Eloy Duran" post.save post.reload post.title # => "On the migration of ducks" post.author.name # => "Eloy Duran”
has_many(1:N)のリレーションの場合
- autosaveオプションは、不要
- postをsaveすると、commentsもsaveされる
class Post has_many :comments # :autosave option is not declared end post = Post.new(title: 'ruby rocks') post.comments.build(body: 'hello world') post.save # => saves both post and comment post = Post.create(title: 'ruby rocks') post.comments.build(body: 'hello world') post.save # => saves both post and comment post = Post.create(title: 'ruby rocks') post.comments.create(body: 'hello world') post.save # => saves both post and comment
rubyのrequire/include/extend/継承/クラス拡張ミックスインまとめ
require/include/extend/継承の違い
require
- 外部ライブラリファイルの読み込み
include
- クラスでモジュールをインクルードすると、モジュールのインスタンスメソッドが手に入る obj.my_method
- クラスメソッドを手に入れるには、クラスの特異クラスでモジュールをインクルードする:MyClass.my_method
- それをショートカットするのがextends。:MyClass.my_method
module A def hello "hello" end end class B include A end test = B.new test.hello => #"hello" B.hello => #"NoMethodError"
extend
- includeはインスタンスメソッドを差し込むのに対して、extendは特異メソッドをインクルードするかたちになる
- だからクラス定義の中でextendすると、クラスの特異メソッド=クラスメソッドになる
- クラスの特異メソッドにインクルード = extend
class C extend A end C.hello => #"hello" test = C.new test.hello => #"NoMethodError" test.extend(A) test.hello => #"hello"
module M1 module ClassMethods def print01 puts "#print01" end end end class C1 extend M1::ClassMethods end C1.print01
クラスの特異メソッドにインクルード
class T01 class << self include Post3 end end T01.print_post3
継承
- rubyでは単一継承のみ
- 多重継承は、mix-in(後述)という概念で対応している
class Ex01 def print01 puts "#print01" end class << self def print02 puts "#print02" end end end class T04 < Ex01 end t04 = T04.new t04.print01 T04.print02
クラス拡張ミックスイン
module Foo def self.included base base.send :include, InstanceMethods base.extend ClassMethods end module InstanceMethods def bar1 puts 'bar1' end end module ClassMethods def bar2 puts 'bar2' end end end class Test include Foo bar2 end t1 = Test.new t1.bar1
実行結果
bar1 bar2
注意点
base.include InstanceMethods
これだと
mixin.rb:3:in `included': private method `include' called for Test:Class (NoMethodError)
といって、怒られる includeは、プライベートメソッドなので、base.sendが必要
ruby - Inheriting class methods from mixins - Stack Overflow
includeしているmoduleをextendする
module Mod1 def module_method1 puts "#module_method1" end end module Core include Mod1 end class T01 extend Core end # Core.module_method1 => error T01.module_method1 t01 = T01.new # t01.module_method1 => error module Mod1 def module_method1 puts "#module_method1" end end module Core include Mod1 end class T01 extend Core module_method1 end
実行結果
#module_method1 #module_method1
メソッド内でのinclude/extend
- メソッドをコールした時にinclude/extendすることができる
module Post def print_post puts "#print_post" end end module Post2 def print_post2 puts "#print_post2" end end class T03 class << self def register # includeでは、エラー extend Post end def register2 class << self include Post2 end end end end # registerを実行してはじめて、extendされる # その後、print_post1が実行できる T03.register T03.print_post # register2を実行してはじめて、includeされる # その後、print_post2が実行できる T03.register2 T03.print_post2