ruby on rails -关联(动态)作用域不工作,直到我在注册文件中做了任何改变



我有两个模型,餐厅和菜系与多对多的关联。这个在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

这些方法可以从模型上的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操作。

我最初没有推荐这种方法的原因是我个人没有使用过它。我很想知道它是怎么工作的。

相关内容

  • 没有找到相关文章

最新更新