Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a concern in a Rails engine?

I'm trying to create a concern inside an engine in order to add/override this functions in the main application which is going to mount this engine. The problem is that I have had problems including the concern in the engine module. It seems that Rails can't find it.

This is my post.rb file in app/models/blorgh/post.rb:

module Blorgh
  class Post < ActiveRecord::Base
    include Blorgh::Concerns::Models::Post
  end
end

And this is my post.rb concern in lib/concerns/models/post.rb:

require 'active_support/concern'

module Concerns::Models::Post
  extend ActiveSupport::Concern

  # 'included do' causes the included code to be evaluated in the
  # conext where it is included (post.rb), rather than be 
  # executed in the module's context (blorgh/concerns/models/post).
  included do
    attr_accessible :author_name, :title, :text
    attr_accessor :author_name
    belongs_to :author, class_name: Blorgh.user_class
    has_many :comments

    before_save :set_author

    private
    def set_author
      self.author = User.find_or_create_by_name(author_name)
    end
  end

  def summary
    "#{title}"
  end

  module ClassMethods
    def some_class_method
      'some class method string'
    end
  end
end

When I run the test/dummy, I got the this error: uninitialized constant Blorgh::Concerns

This is my blorgh.gemspec:

$:.push File.expand_path("../lib", __FILE__)

# Maintain your gem's version:
require "blorgh/version"


# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
  s.name        = "blorgh"
  s.version     = Blorgh::VERSION
  s.authors     = ["***"]
  s.email       = ["***"]
  s.homepage    = "***"
  s.summary     = "Engine test."
  s.description = "Description of Blorgh."

  s.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.rdoc"]
  s.test_files = Dir["test/**/*"]

  s.add_dependency "rails", "~> 3.2.8"
  s.add_dependency "jquery-rails"

  s.add_development_dependency "sqlite3"
end

Can someone help me with this?

like image 851
Dagosi Avatar asked Jan 08 '13 15:01

Dagosi


People also ask

What are concerns in Rails?

A Rails Concern is a module that extends the ActiveSupport::Concern module. Concerns allow us to include modules with methods (both instance and class) and constants into a class so that the including class can use them. The code inside the included block is evaluated in the context of the including class.

How does a Rails engine work?

Rails looks first in the application's ( test/dummy ) app/views directory and then in the engine's app/views directory. When it can't find it, it will throw this error. The engine knows to look for blorgh/comments/_comment because the model object it is receiving is from the Blorgh::Comment class.

Is devise a Rails engine?

The well-known devise gem , for example, is based on Rails engines. But what is it exactly? Well, simply put a Rails engine is the miniature edition of a Rails application. It comes with an app folder, including controllers, models, views, routes, migrations...


1 Answers

When using engines, you need to keep track of the load order, especially when changing behavior of the main app. Suppose your engine is called "engine_name", you should have this file: engine_name/lib/engine_name/engine.rb. This is one place to include your Concerns.

Bundler.require

module EngineName
  class Engine < ::Rails::Engine
    require 'engine_name/path/to/concerns/models/post'

    initializer 'engine_name.include_concerns' do
      ActionDispatch::Reloader.to_prepare do
        Blorgh::Post.send(:include, Concerns::Models::Post)
      end
    end

    # Autoload from lib directory
    config.autoload_paths << File.expand_path('../../', __FILE__)

    isolate_namespace EngineName
  end
end

This way you make sure everything is loaded alright, but be very careful using Concerns and maybe reconsider using dependency injection by refactoring Blorgh::Post to deal with different configurations.

like image 192
knugie Avatar answered Sep 22 '22 14:09

knugie