【问题标题】:How to set has_many association between parent app's model and mounted engine's model?如何设置父应用模型和挂载引擎模型之间的has_many关联?
【发布时间】:2015-01-26 17:50:32
【问题描述】:

按照RailsGuides 的指令,我在我的应用程序中创建了一个博客系统引擎。此博客引擎挂载为 /blog。

RailsGuides 展示了如何将 belongs_to 关联添加到已安装引擎的 Article 模型。但是,父应用的 User 模型仍然需要 has_many 关联到引擎的 Article 模型,该模型位于不同的命名空间中。

如何设置父应用模型和挂载引擎模型的has_many关联?

  • Ruby 2.2.0
  • Rails 4.2.0

提前致谢。

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4


    【解决方案1】:

    在rails应用程序中,你知道你包含什么模块,所以你可以简单地用类名指定关系;)

    has_many :articles, class_name: 'Blog::Article'
    

    检查这是否是您的数据库适配器的正确语法,例如我将它用于 Mongoid,但它应该与 ActiveRecord AFAIK 相同

    【讨论】:

    • 谢谢!您是否也可以提供迁移服务?
    • 我的意思是我不知道在这种情况下创建迁移的正确方法。
    • has_many 只是对您的数据库适配器的提示(在大多数情况下),外键通常是另一边的 user_id(belongs_to 所在的位置),所以您不要不需要任何迁移
    • 啊,我明白了,谢谢。也许我误解了关联是如何运作的;)
    【解决方案2】:

    接受的答案需要手动修改 main_app 的父模型,以便将 has_many 关系设置为引擎的子模型。因此,每次将引擎添加到 main_apps 时,您都必须进入 main_apps 模型并手动设置所有必需的关系。

    一个更健壮但更复杂的解决方案是在引擎中使用装饰器模式,以便引擎自动配置 main_app 的父模型及其所需的关系。

    通过使用此方法,您只需在 main_app 中向引擎初始化程序添加一个设置,引擎将处理其余部分。

    在引擎中:

    blog.gemspec.rb

    s.add_dependency 'decorators' #this will install the decorators gem for use in engine
    

    lib/blog/blog.rb

    module Blog
      class Engine < ::Rails::Engine
        isolate_namespace Blog
        engine_name 'blog'
    
        #to set up main_app objects via decorators in engine
        config.to_prepare do
          Decorators.register! Engine.root, Rails.root
        end
    
      end
    end
    

    lib/blog.rb

    require 'decorators'
    
    module Blog
    
      mattr_accessor :user_class #Can now reference this setting as Blog.user_class
    
    class << self
    
        #the following lets us add functionality to main_app user model
    
        def decorate_user_class!
          Blog.user_class.class_eval do
            has_many :articles, :class_name => "Blog::Article", :foreign_key => "user_id"
          end
        end
    
      end
    end
    

    app/decorators/lib/blog/user_class_decorator.rb

    if Blog.user_class
      Blog.decorate_user_class!
    else
      raise "Blog.user_class must be set in main_app blog.rb initializer"
    end
    

    在主应用中:

    app/initializers/blog.rb

    Blog.user_class = User
    

    如果您从主应用程序运行 rails 控制台,您将看到已正确设置关系。引擎中的装饰器模式也可用于以不同方式扩展 main_app 的模型和控制器,而不仅仅是 Activerecord 关系。实现了几乎完全的解耦!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多