Rails 3 Engines

Hi,

I’m experimenting a bit with Rails3 and the Rails::Engine functionality.
But there are a fiew points where I get stuck:

application_helper.rb : it looks like it is not loaded. When I call some
method helpers in my application defined in my engines application
helper, I get an undefined method error

application_controller.rb : same problem like with the
application_helper.rb

assets like images, css, js that are stored in the engine are not loaded
into the application

I must be overseeing something, but since these are my first steps into
Rails Engine and Rails 3, I just can’t figure out what it is. Everything
else like other controllers, helpers, views and routes are loaded
perfectly
Sincerely yours

It seems that the application_helper and controller are loaded. But once
you override them (just the files, not the methods) it take the
application files.
this means that you can’t just override the application helper and
controller methods individualy. Is there a workaround for this? I guess
you could create a module to include or a class to inherit from?

Still no luck with the assets though. Any help would be great.

Hi Michael,

First of all, finding good resources about Rails 3 engines is really
hard. I spent a lot of hours to figure out how it works. That being
said, back to your questions.

Michael R. wrote:

It seems that the application_helper and controller are loaded. But once
you override them (just the files, not the methods) it take the
application files.
this means that you can’t just override the application helper and
controller methods individualy. Is there a workaround for this? I guess
you could create a module to include or a class to inherit from?

Take a look at Devise source code. They include helper methods within
the ActionView / Controller modules.
Another problem with helpers inside engine. In production, other helpers
than the one assigned to the current controller are not loaded. Which
means that if you have your PageController, you won’t be able to use
methods defined in SitesHelper. The only solution I found is to include
them when you load your engine.rb file.

Still no luck with the assets though. Any help would be great.

This one seems “obvious”. For instance, how can Nginx do to serve assets
from an engine ? There is no way it can serve them, so we need to help
it. The reason I found after reviewing a lot of projects is to create a
generator inside your gem copying your assets file.

Good luck Michael :slight_smile:

Hi Didier

could you tell me how to include those helpers from my engine? I have
tried several methods like

  class Engine < Rails::Engine
      config.to_prepare do
          ApplicationController.helper(Admin::MetasHelper)
      end
  end

or

ActionView::Base.send :include, Admin::MetasHelper

but none seem to work :s

Secondly, I allready knew that accessing assets from gems would be
impossible. The only difference was, that I thought that their might be
a special helper like the rails_engine plugin for Rails 2.x .
But just for the info, how do I access files from my gem/engine? When I
create a generator, how does the filepath usualy work?

Hi Didier,

thanks for the info. I found another way to load the helpers.

In my lib/my_engine.rb file I did the following:

  ActiveSupport::Dependencies.load_paths << File.dirname(__FILE__) + 

“/…/app/helpers”
ActiveSupport::Dependencies.load_once_paths.delete
File.dirname(FILE) + “/…/app/helpers”
ActionController::Base.helper MetasHelper

so lib/my_engine.rb looks like this:

if defined?(Rails)
require ‘rails’

module MyEngine
module Meta
class Engine < Rails::Engine
end
end
end

module Admin
ActiveSupport::Dependencies.load_paths << File.dirname(FILE) +
“/…/app/helpers”
ActiveSupport::Dependencies.load_once_paths.delete
File.dirname(FILE) + “/…/app/helpers”
ActionController::Base.helper MetasHelper
ActionController::Base.helper CategoriesHelper
ActionController::Base.helper ThemesHelper
end
end

I had to insert the ActiveSupport and ActionController within a Admin
module since its namespaced.

Seems like
ActiveSupport::Dependencies.load_once_paths.delete
File.dirname(FILE) + “/…/app/helpers”

is not realy nessacary. It also works without that line.

What I’m woundering now is if It’s possible to load all helpers without
specifying them individualy

could you tell me how to include those helpers from my engine? I have
tried several methods like

  class Engine < Rails::Engine
      config.to_prepare do
          ApplicationController.helper(Admin::MetasHelper)
      end
  end

I spent some much time on this, trying all the different ways of
including those helpers (ie not related to controllers), without any
success (sometimes it worked in dev env but not in prod, …etc).
So I came up with another approach.
Actually, my engine controllers inherit from a base controller. So
inside this base one, I added the following lines:

Dir[File.dirname(FILE) + “/…/…/helpers/**/*_helper.rb”].each do
|file|
helper “admin/#{File.basename(file, ‘.rb’).gsub(/_helper$/, ‘’)}”
end

Even if it is not super clean, it does the trick for me. If anyone has a
better way of doing it, let me know :slight_smile:

Secondly, I allready knew that accessing assets from gems would be
impossible. The only difference was, that I thought that their might be
a special helper like the rails_engine plugin for Rails 2.x .
But just for the info, how do I access files from my gem/engine? When I
create a generator, how does the filepath usualy work?

Take a look at my generator:

http://github.com/did/locomotive/blob/master/lib/generators/locomotive/assets/assets_generator.rb

Your solution looks good ! Are you sure that even your first statement
(ActiveSupport::Dependencies.load_paths…) is needed ?

What I’m woundering now is if It’s possible to load all helpers without
specifying them individualy

Something like that ?

module Admin

adjust path

Dir[File.dirname(FILE) + “/…/…/helpers/**/*_helper.rb”].each do
|file|
ActionController::Base.helper File.basename(file,
‘.rb’).classify.constantize
end
end

Well, with my method it seemed like it was needed.

I tryed your way, but it doesn’t seem to work.

/Library/Ruby/Gems/1.8/gems/activesupport-3.0.0.beta4/lib/active_support/inflector/methods.rb:103:in
`constantize’: uninitialized constant MediasHelper (NameError)

Even when I add the loadpaths

module Admin
ActiveSupport::Dependencies.load_paths << File.dirname(FILE) +
“/…/app/helpers”
Dir[File.dirname(FILE) +
“/…/app/helpers/**/*_helper.rb”].each do |file|
ActionController::Base.helper File.basename(file,
‘.rb’).classify.constantize
end
end

Didier Did wrote:

Your solution looks good ! Are you sure that even your first statement
(ActiveSupport::Dependencies.load_paths…) is needed ?

What I’m woundering now is if It’s possible to load all helpers without
specifying them individualy

Something like that ?

module Admin

adjust path

Dir[File.dirname(FILE) + “/…/…/helpers/**/*_helper.rb”].each do
|file|
ActionController::Base.helper File.basename(file,
‘.rb’).classify.constantize
end
end

Well, with my method it seemed like it was needed.

That’s right but how can your engine know what helpers are not tied to
controllers ? mmmhh, that’s definitely doable but it’s not worth it.

I tryed your way, but it doesn’t seem to work.

I think that’s because of namespacing. It expects Admin::MediasHelper
but that’s weird since you call it from your Admin module.
Maybe you should try to force it ?

ActionController::Base.helper "admin/#{File.basename(file, ‘.rb’)
".camelize.constantize

I’m thinking, maybe you could have the best of the two worlds.

%w{metas categories themes}.each do |name|
ActionController::Base.helper
“Admin::#{name.camelize}Helper”.constantize
end

What do you think about it ?

/Library/Ruby/Gems/1.8/gems/activesupport-3.0.0.beta4/lib/active_support/inflector/methods.rb:103:in
`constantize’: uninitialized constant MediasHelper (NameError)

Even when I add the loadpaths

module Admin
ActiveSupport::Dependencies.load_paths << File.dirname(FILE) +
“/…/app/helpers”
Dir[File.dirname(FILE) +
“/…/app/helpers/**/*_helper.rb”].each do |file|
ActionController::Base.helper File.basename(file,
‘.rb’).classify.constantize
end
end

Didier Did wrote:

Your solution looks good ! Are you sure that even your first statement
(ActiveSupport::Dependencies.load_paths…) is needed ?

What I’m woundering now is if It’s possible to load all helpers without
specifying them individualy

Something like that ?

module Admin

adjust path

Dir[File.dirname(FILE) + “/…/…/helpers/**/*_helper.rb”].each do
|file|
ActionController::Base.helper File.basename(file,
‘.rb’).classify.constantize
end
end

Ok, found a “solution”

ActiveSupport::Dependencies.load_paths << File.dirname(FILE) +
“/…/app/helpers”
Dir[File.dirname(FILE) + “/…/app/helpers/**/*_helper.rb”].each do
|file|
ActionController::Base.helper
“Admin::#{File.basename(file,’.rb’).camelize}”.constantize
end

not wrapped inside my Admin module. This seems to work fine. Tried
without the ActiveSupport::Dependencies, but then it didn’t work out:
uninitialized constant error for my helper.

Anyway, nice working with you Didier to get working and dynamic solution
for this problem.

Michael R. wrote:

Ok, found a “solution”

ActiveSupport::Dependencies.load_paths << File.dirname(FILE) +
“/…/app/helpers”
Dir[File.dirname(FILE) + “/…/app/helpers/**/*_helper.rb”].each do
|file|
ActionController::Base.helper
“Admin::#{File.basename(file,’.rb’).camelize}”.constantize
end

not wrapped inside my Admin module. This seems to work fine. Tried
without the ActiveSupport::Dependencies, but then it didn’t work out:
uninitialized constant error for my helper.

Anyway, nice working with you Didier to get working and dynamic solution
for this problem.

I think the best way to load your helpers would be to use the new
initializer method, for my themes engine I used this:

initializer ‘themes.helper’ do |app|
ActionView::Base.send :include, ThemesHelper
end

Hope this helps.

Matt

Anyway, nice working with you Didier to get working and dynamic solution
for this problem.

Thanks ! Same thing :slight_smile:

Hi Matt,

where exactly do you put that initializer?

thx, just got it ;). stupid question . Thx for the hint though. My
earlier solution broke down when upgrading from Beta4 to RC1

This goes in your main engines class:

module SomeModule
class SomeClass < ::Rails::Engine
initializer ‘some_class.helper’ do |app|
ActionView::Base.send :include, SomeHelper
end
end
end

Cheers

Matt

On 31 Jul 2010, at 18:43, Michael R. wrote:

Hi Matt,

where exactly do you put that initializer?


Posted via http://www.ruby-forum.com/.


Engine-Users mailing list
[email protected]
http://lists.rails-engines.org/listinfo.cgi/engine-users-rails-engines.org

Matthew Crouch
Mobilezilla

Telephone: +44 (0) 7958 592 326
Email: [email protected]
Web: http://www.mobilezil.la
Skype: mobilezilla

Please consider the environment before printing out this email.

The contents of this email are confidential to the addressee
and are intended solely for the recipients use. If you are not
the addressee, you have received this email in error.
Any disclosure, copying, distribution or action taken in
reliance on it is prohibited and may be unlawful.

Any opinions expressed in this email are those of the author
personally.

All email communications are recorded for monitoring purposes.