我有两个模型,餐厅和菜系与多对多的关联。这个在app/admin/restaurant。rb
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
问题是每当我删除或添加新的菜系时,范围不会改变,直到我更改我的admin/restaurant。rb文件。我如何解决这个问题?
我可以通过添加admin/restaurant.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
在这里找到了解决方案
我不确定动态定义作用域的方法,至少使用scope
方法。
scope
方法的替代方法是定义一个类方法,据我所知,它完成了同样的事情。
也就是说
scope("All"){|scope| scope.order("created_at desc")}
与
相同# in a Class
class << self
def All
order("created_at desc")
end
end
您可以使用这个方法动态地创建类方法(取自ruby- definition -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
这些方法可以从模型上的save
和destroy
钩子调用,即:
# 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操作。
我最初没有推荐这种方法的原因是我个人没有使用过它。我很想知道它是怎么工作的。