2016-09-14 5 views
0

Rails 4.2でイニシャライザを使用してメソッドをActiveRecordモデルに追加しようとしています。ただし、イニシャライザでクラスを再オープンするだけで、既存の属性アクセサが破損します。イニシャライザのクラスを再オープンすると、属性アクセサが破損する

モデルアプリ/モデル/ thing.rb:

class Thing < ActiveRecord::Base 
end 

移行DB /移行/ 20160914144414_create_things.rb:

class CreateThings < ActiveRecord::Migration 
    def change 
    create_table :things do |t| 
     t.integer :test_field 
     t.timestamps null: false 
    end 
    end 
end 

初期設定/初期化子/ thing.rb:

class Thing 
    def self.new_method 
    "hello" 
    end 
end 

テストファイル/ models/thing_test.rb:

require File.expand_path("../../test_helper", __FILE__) 

class ThingTest < ActiveSupport::TestCase 
    test "the truth" do 
    thing = Thing.new 
    thing.test_field = 1 
    puts thing.new_method 
    end 
end 

私はここに私のテストを実行して、私が得るものです:

❯❯❯ rtest test/models/thing_test.rb 
    1) Error: 
ThingTest#test_the_truth: 
NoMethodError: undefined method `test_field=' for #<Thing:0x00000101464658> 
    test/models/thing_test.rb:6:in `block in <class:ThingTest>' 

私はクラスにメソッドを追加するには、この代替構文を使用している場合は、それが動作:

Thing.class_eval do 
    def self.new_method 
    "hello" 
    end 
end 

私は「推測しますこのようにしてうれしいですが、クラスを再開するだけでは効果がないのはなぜですか。

+0

私はイニシャライザでクラスを作成していません。再オープンしてメソッドを追加しようとしています。 Rubyが許可していることを理解している –

+0

イニシャライザは最初に実行されません。イニシャライザの実行時にクラスが既に存在します。 –

+0

ファイルの先頭にデバッガー文を置いています。デバッガでは 'Thing.superclass'をクエリでき、ActiveRecord :: Baseを取得します。私はThingのインスタンスを作成し、それにtest_fieldを呼び出します。 –

答えて

1

重要なことは、クラスを再オープンしていないことです。新しいものを定義しています。開発とテストでは、クラスは最初に使用されるときにロードされます。イニシャライザにThingを定義することによって、thing.rbファイルがロードされるのを防ぐことができます。

あなたは新しいクラスを定義していないThing.class_eval使用する場合はそうthing.rbから負荷Thingレール:この時点では、Thingに追加するのではなく、それを交換します。

0

あなたは継承のないメソッドを宣言しているので、起こったと思います。デフォルトアクセサーはActiveRecord::Baseです。新しいメソッドを宣言すると、継承者のすべてがオーバーライドされます。

+0

'Class Thing

2

ファイルの先頭にデバッガー文を挿入しました。デバッガで私はThing.superclassを問い合わせることができ、私はActiveRecord :: Baseを取得します。私はThingのインスタンスを作成し、それにtest_fieldを呼び出します。

実験を観察するだけで、その結果が変わります。デバッガのステートメントで停止すると、クラスにはが存在しません。しかし、デバッガコンソールでThingと評価した瞬間、が自動的にロードされます。です。

実際のイニシャライザでできることは、モデルの読み込みをトリガすることです。

# initializers/thing.rb 
Thing # trigger autoloading 
class Thing 
    ... 
end 


# or 
require 'app/models/thing.rb' # load explicitly 
class Thing 
    ... 
end 
+0

説明をいただきありがとうございます - 私自身は結論に達していません! –

関連する問題