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