Forum: Rails Engines Rails 3 Engines

Posted by Michael Rigart (damick)
on 2010-06-05 13:48
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
Posted by Michael Rigart (damick)
on 2010-06-05 16:35
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.
Posted by Didier Did (did)
on 2010-06-12 01:55
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 Rigart 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 :-)


Posted by Michael Rigart (damick)
on 2010-06-17 11:04
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?
Posted by Didier Did (did)
on 2010-06-17 11:20
> 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 :-)


> 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/g...
Posted by Michael Rigart (damick)
on 2010-06-17 11:46
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.

Posted by Michael Rigart (damick)
on 2010-06-17 11:59
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
Posted by Didier Did (did)
on 2010-06-17 12:18
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

Posted by Michael Rigart (damick)
on 2010-06-17 13:01
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
Posted by Didier Did (did)
on 2010-06-17 13:11
> 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
Posted by Michael Rigart (damick)
on 2010-06-17 14:19
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.
Posted by Didier Did (did)
on 2010-06-17 14:36
> Anyway, nice working with you Didier to get working and dynamic solution 
> for this problem.

Thanks ! Same thing :-)
Posted by Matthew Crouch (mobilezilla)
on 2010-07-24 12:23
Michael Rigart 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
Posted by Michael Rigart (damick)
on 2010-07-31 19:43
Hi Matt,

where exactly do you put that initializer?
Posted by Matthew Crouch (mobilezilla)
on 2010-07-31 19:46
(Received via mailing list)
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 Rigart wrote:

> Hi Matt,
> 
> where exactly do you put that initializer?
> 
> -- 
> Posted via http://www.ruby-forum.com/.
> _______________________________________________
> Engine-Users mailing list
> Engine-Users@lists.rails-engines.org
> http://lists.rails-engines.org/listinfo.cgi/engine...

--

Matthew Crouch
Mobilezilla

Telephone:    +44 (0) 7958 592 326
Email:             mcrouch@mobilezil.la
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.
Posted by Michael Rigart (damick)
on 2010-07-31 19:54
thx, just got it ;). stupid question . Thx for the hint though. My 
earlier solution broke down when upgrading from Beta4 to RC1
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.