1

私は、多対多関連の2つのモデル、レストラン、料理を持っています。そして、私はこの関連付けられた(動的)スコープは、レジスタファイルに変更を加えるまで機能しません。

ActiveAdmin.register Restaurant do 
    scope("All"){|scope| scope.order("created_at desc")} 
    Cuisine.all.each do |c| 
    scope(c.name) { |scope| scope.joins(:cuisines).where("cuisines.id=?",c.id)} 
    end 
end 

私のアプリ/管理/ restaurant.rbでの問題は、私は新しい料理を削除したり、追加するたびに、私は私の管理者/ restaurant.rbファイルへの変更を行うまでのスコープが変更されないできました。この問題を解決するにはどうすればよいですか?

答えて

1

私は、少なくともscope方法を使用して、動的スコープを定義する方法のか分かりません。

scopeメソッドの代わりに、私が知っている限り同じことを達成するクラスメソッドを定義しています。言い換えれば

scope("All"){|scope| scope.order("created_at desc")} 

あなたは動的にこのメソッドを使用してクラスのメソッドを作成することができます

# in a Class 

class << self 
    def All 
    order("created_at desc") 
    end 
end 

と同じである(ruby-defining-class-methodsから撮影:

class Object 
    def meta_def name, &blk 
    (class << self; self; end).instance_eval { define_method name.to_s, &blk } 
    end 
end 

私はよ次のコードを使用して、生成されたクラスメソッドを削除します。

class Object 
     def meta_undef name 
     (class << self; self; end).class_eval { remove_method name.to_sym } 
     end 
end 

これらの方法はすなわち、あなたのモデルにsavedestroyフックから呼び出すことができます。:

# in a Model 
def save(*args) 
    self.class.meta_def(name) do 
    joins(:cuisines).where("cuisines.id=?",c.id) 
    end 
    super(*args) 
end 

def destroy(*args) 
    self.class.meta_undef(name) 
    super(*args) 
end 

レコードが作成または削除されるたびに続いて、スコープが更新されます。このアプローチの長所と短所があります。メソッドをオンザフライで定義することは明らかですが、これはリモートコード実行に対して脆弱です。

個人的には、クラスメソッド(つまりスコープ)を動的に定義することを止め、引数を受け入れるようにしましょう。例:あなたのコメントに応答する

# This is with standard ActiveRecord, not sure about ActiveAdmin 
    class Restaurant < ActiveRecord::Base 
    def self.All 
     order("created_at desc") 
    end 
    end 
    class Cuisine < ActiveRecord::Base 
    def self.by_name(name) 
     Restaurant.all.joins(:cuisines).where("cuisines.name=?", name) 
    end 
    end 

    Cuisine.by_name("something") 
    Restaurant.all.All 
    Restaurant.All 

編集は:

load(file)ソースを再ロードします。あなたは次のことを試みることができるので:

# in a model 
def save(*args) 
    load(Rails.root.join("app", "models", "THIS_MODEL_FILE.rb") 
    super 
end 

def destroy(*args) 
    load(Rails.root.join("app", "models", "THIS_MODEL_FILE.rb") 
    super 
end 

ボンネットの下に作成および更新の両方のために、saveが呼び出されます。オーバーライドして、destroyはすべてのCRUD操作をカバーします。

私がこのアプローチを最初に推奨しなかったのは、私が個人的に使ったことがないからです。私はそれがどのように機能するか知りたいと思うだろう。

+0

おかげで解決策を見つけた時はいつでも任意の料理の変更。 –

+0

OK @ AsnadAtta、私は私の答えに応答を追加しました。投稿の最後にある編集をご覧ください。 –

2

私の管理者/レストランで追加することでこれを解決できました。RB

controller do 
    before_filter :update_scopes, :only => :index 
    def update_scopes 
    resource = active_admin_config 

    Cuisine.order("created_at ASC").each do |m| 
     next if resource.scopes.any? { |scope| scope.name == m.name} 
     resource.scopes << (ActiveAdmin::Scope.new m.name do |restaurants| 
     restaurants.joins(:cuisines).where("cuisines.id=?", m.id) 
     end) 
    end 

    resource.scopes.delete_if do |scope| 
     !(Cuisine.all.any? { |m| scope.name == m.name }) 
    end 
    resource.scopes.unshift(ActiveAdmin::Scope.new "All" do |restaurants| restaurants end) 
    end 

は、私たちは、レジスタファイルをリロードすることができ、最大示す新しい料理をファイル管理/ restaurant.rbで変更を行うたびのより多くの事であり、応答をhere

+1

解決策を探していい仕事。スコープが配列のようになっていることを理解できませんでした。誰かが「すべて」という名前の料理を追加するとどうなりますか?幸いにも、Railsはエラーを投げ、デフォルトの 'Restaurant.all'を上書きしません。 –

関連する問題