4

私は、お互いにHABTM関係を持つ2つのActiveRecordモデルを持っています。 チェックボックスをオンにしてゾーンを追加できるようなフォームでAccessUnitを追加すると、渡されたアクセスユニットをシリアル化できないため、AccessUnitUpdaterJobをエンキューできないという例外が発生します(識別子が欠落しているため)。プライマリオブジェクトでsaveを手動で呼び出すと、問題は解決されますが、これは回避策であり、適切な修正ではありません。Rails HABTM after_addコールバックは、プライマリオブジェクトを保存する前に起動します。

TLDR;メインオブジェクトが保存される前にafter_addコールバックがトリガーされたようです。これがRailsのバグか期待される振る舞いであるかどうかは確かに分かりません。私の視点では

class AccessUnit < ApplicationRecord 
    has_and_belongs_to_many :zones, after_add: :schedule_access_unit_update_after_zone_added_or_removed, after_remove: :schedule_access_unit_update_after_zone_added_or_removed 

    def schedule_access_unit_update_after_zone_added_or_removed(zone) 
    # self.save adding this line solves it but isn't a proper solution 
    puts "Access unit #{name} added or removed to zone #{zone.name}" 

    # error is thrown on this line 
    AccessUnitUpdaterJob.perform_later self 
    end 
end 

class Zone < ApplicationRecord 
    has_and_belongs_to_many :access_units 
end 
+0

少なくとも、http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.htmlは、「Association extensions」セクションでafter_addが保存前にトリガーされるかどうかを指定する必要があります。 – kshikama

答えて

2

ActiveJob::SerializationError in AccessUnitsController#create 

Unable to serialize AccessUnit without an id. (Maybe you forgot to call save?) 

あなたが問題のコンテキストを見ることができるように、ここにいくつかのコードです:私は、私が遭遇した正確なエラーがあるのRails 5.

を使用していますそれはバグではありません。すべてのものが期待通りに機能します。このグラフを保存する前に、オブジェクトの複雑なグラフを作成することができます。この作成フェーズでは、関連付けにオブジェクトを追加できます。これはafter_addといい、after_saveではないので、このコールバックを起動する時点です。例えば

class Post 
    has_many :tags, before_add: :check_state 

    def check_state(_tag) 
    if self.published? 
     raise CantAddFurthorTags, "Can't add tags to a published Post" 
    end 
    end 
end 

@post = Post.new 
@post.tags.build name: "ruby" 
@post.published = true 
@post.tags.build name: "rails" # <= you wan't to fire the before_add callback now, to know that you can't add this new object 
@post.save! # <= and not here, where you can't determine which object caused the error 

あなたは著書「Railsの4ウェイ」

内でこれらのコールバックについて少しを読むことができます:それは、より理にかなって before_addコールバックと多分

@post.tags.build name: "ruby" # <= now you add the objects 
@post.tags.build name: "rails" # <= now you add the objects 
@post.save! # <= now it is to late, for this callback, you added already multiple objects 

あなたの場合は、あなたのロジックを再考する必要があります。おそらくafter_saveコールバックを使用することができます。 私の2セント:コールバックからサービスオブジェクトへの切り替えを検討してください。 コールバックはコストなしではありません。デバッグとテストは必ずしも容易ではありません。

関連する問題