http://blog.bigbinary.com/2017/05/30/rails-5-1-adds-delegate-missing-to.html
rails 5.1 添加了 delegate_missing_to 方法
实验如下:
rails g model user usename:string password:string email:string
rails g model book title:string user:references
rails db:migrate
生成如下 model
class User < ApplicationRecord
has_many :books
end
class Book < ApplicationRecord
belongs_to :user
end
在 console 中实验
User.create(username:'test', password:'123456', email:'[email protected]')
Book.create(user:User.last, title:'this is a book')
irb(main):017:0> Book.last.user
Book Load (0.3ms) SELECT `books`.* FROM `books` ORDER BY `books`.`id` DESC LIMIT 1
User Load (0.2ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
=> #<User id: 1, username: "test", password: "123456", email: "[email protected]", created_at: "2017-06-02 01:55:54", updated_at: "2017-06-02 01:55:54">
irb(main):018:0> Book.last.username
Book Load (0.4ms) SELECT `books`.* FROM `books` ORDER BY `books`.`id` DESC LIMIT 1
NoMethodError: undefined method `username' for #<Book >
from (irb):18
可以看到直接访问 username 会报 method missing
在 book 中添加 delegate_missing_to
class Book < ApplicationRecord
belongs_to :user
delegate_missing_to :user
end
try again
irb(main):020:0> Book.last.username
Book Load (0.2ms) SELECT `books`.* FROM `books` ORDER BY `books`.`id` DESC LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
=> "test"
看实现 pr: https://github.com/rails/rails/pull/23930/files#r64312481
# The target can be anything callable withing the object. E.g. instance
# variables, methods, constants ant the likes.
def delegate_missing_to(target)
target = target.to_s
target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
module_eval <<-RUBY, __FILE__, __LINE__ + 1
def respond_to_missing?(name, include_private = false)
#{target}.respond_to?(name, include_private)
end
def method_missing(method, *args, &block)
#{target}.send(method, *args, &block)
end
RUBY
end
好处:1:可以少写一点代码,在比较多的 delegate 指向同一个 asocciation 的时候;2:可以向其他非动态语言炫技