ActiveRecordで動的に生成されるsend
メソッドとObject#send
は衝突したらどうなるのか?という話です。
結論は、つかえます。
実際に試してみます。 Railsアプリケーションを準備します。
rbenv local 3.3.4 bundle init bundle add rails bundle exec rails new . bundle update bin/rails g model WebSocket send:string bin/rails db:migrate
動かしてみましょう。
ledsun@MSI:~/rails_7_1►bin/rails c Loading development environment (Rails 7.2.0) rails71(dev)> WebSocket.new.send => nil rails71(dev)> WebSocket.new.send(:send) (rails71):2:in `<main>': wrong number of arguments (given 1, expected 0) (ArgumentError)
send
という引数0個のメソッドがあります。
send
カラムに対応したメソッドです。
Object#send
は呼べません。
せっかくなので、send
メソッドを定義してる場所を探しましょう。
rails71(dev)> WebSocket.new.method(:send).source_location => ["/home/ledsun/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activemodel-7.2.0/lib/active_model/attribute_methods.rb", 269]
rails/activemodel/lib/active_model/attribute_methods.rb at main · rails/rails · GitHub
こんな感じの関数が定義されています。
def define_attribute_methods(*attr_names) ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner| attr_names.flatten.each do |attr_name| define_attribute_method(attr_name, _owner: owner) aliases_by_attribute_name[attr_name.to_s].each do |aliased_name| generate_alias_attribute_methods owner, aliased_name, attr_name end end end end
binding.break
をいれて止めてみましょう。
ledsun@MSI:~/rails_7_1►bin/rails c Loading development environment (Rails 7.2.0) rails71(dev)> WebSocket.new [263, 272] in ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activemodel-7.2.0/lib/active_model/attribute_methods.rb 263| # def clear_attribute(attr) 264| # send("#{attr}=", nil) 265| # end 266| # end 267| def define_attribute_methods(*attr_names) => 268| binding.break 269| ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner| 270| attr_names.flatten.each do |attr_name| 271| define_attribute_method(attr_name, _owner: owner) 272| aliases_by_attribute_name[attr_name.to_s].each do |aliased_name| =>#0 ActiveModel::AttributeMethods::ClassMethods#define_attribute_methods(attr_names=[["id", "send", "created_at", "updated_at...) at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activemodel-7.2.0/lib/active_model/attribute_methods.rb:268 #1 block in define_attribute_methods at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/attribute_methods.rb:115 # and 46 frames (use `bt' command for all frames)
bt
コマンドでバックトレースを見てみます。
(rdbg) bt # backtrace command =>#0 ActiveModel::AttributeMethods::ClassMethods#define_attribute_methods(attr_names=[["id", "send", "created_at", "updated_at...) at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activemodel-7.2.0/lib/active_model/attribute_methods.rb:268 #1 block in define_attribute_methods at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/attribute_methods.rb:115 #2 [C] Monitor#synchronize at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/attribute_methods.rb:108 #3 ActiveRecord::AttributeMethods::ClassMethods#define_attribute_methods at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/attribute_methods.rb:108 #4 ActiveRecord::Core#init_internals at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/core.rb:789 #5 ActiveRecord::Persistence#init_internals at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/persistence.rb:817 #6 ActiveModel::Dirty#init_internals at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activemodel-7.2.0/lib/active_model/dirty.rb:366 #7 ActiveRecord::AttributeMethods::Dirty#init_internals at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/attribute_methods/dirty.rb:197 #8 ActiveRecord::Timestamp#init_internals at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/timestamp.rb:103 #9 ActiveRecord::Associations#init_internals at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/associations.rb:76 #10 ActiveRecord::AutosaveAssociation#init_internals at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/autosave_association.rb:279 #11 ActiveRecord::Transactions#init_internals at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/transactions.rb:434 #12 ActiveRecord::TouchLater#init_internals at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/touch_later.rb:50 #13 ActiveRecord::Core#initialize(attributes=nil) at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/core.rb:455 #14 [C] Class#new at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/inheritance.rb:76 #15 ActiveRecord::Inheritance::ClassMethods#new(attributes=nil, block=nil) at ~/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/activerecord-7.2.0/lib/active_record/inheritance.rb:76
new
メソッドまで辿れます。
ActiveRecordを継承したクラスを最初にnew
したときにsend
メソッドが定義されるようです。