Rails3 Engine -- Controller scoped inside engine module returning load error by client app
I just created my first engine. It adds a couple of new routes like so:
Rails.application.routes.draw do
scope :module => 'contact' do
get "contact", :to => 'contacts#new'
get "contact/send_email", :to => 'contacts#send_email', :as => 'send_email'
end
end
Then, in /websites/Engines/contact/app/controllers/contacts_controller.rb, I have:
module Contact
class ContactsController < ApplicationController
# Unloadable marks your class for reloading between requests
unloadable
def new
@contact_form = Contact::Form.new
end
def send_email
@contact_form = Contact::Form.new(params[:contact_form])
if @contact_form.valid?
Notifications.contact(@contact_form).deliver
redirect_to :back, :notice => 'Thank you! Your email has been sent.'
else
render :new
end
end
end
end
I loaded it up in the client app's console to prove to my开发者_C百科self some basics were working and quickly got this load error (which I then confirmed by reproducing the issue in a browser):
ruby-1.8.7-p302 > Contact::Form.new
=> #<Contact::Form:0x2195b70>
ruby-1.8.7-p302 > app.contact_path
=> "/contact"
ruby-1.8.7-p302 > r = Rails.application.routes; r.recognize_path(app.contact_path)
LoadError: Expected /websites/Engines/contact/app/controllers/contacts_controller.rb to define ContactsController
And there you have it; /contact gets to the engine's contacts_controller.rb but the fact the controller is inside the module Contact makes it unrecognizable.
What am I doing wrong?
Your app/controllers/contacts_controller.rb
is actually defining the Contact::ContactsController
, not the ContactsController
that Rails expects.
The problem is with your routes, they should be defined like this:
Rails.application.routes.draw do
scope :module => 'contact' do
get "contact", :to => 'contact/contacts#new'
get "contact/send_email", :to => 'contact/contacts#send_email', :as => 'send_email'
end
end
Thanks to @ryan-bigg and @nathanvda their answers in conjunction fixed this issue for me. In short, I ended up using the following routes:
Rails.application.routes.draw do
scope :module => 'contact' do
get "contact", :to => 'contacts#new'
post "contact/send_email", :to => 'contacts#send_email', :as => 'send_email'
end
end
with the following controller:
module Contact
class ContactsController < ApplicationController
def new
@contact_form = Contact::Form.new
end
def send_email
@contact_form = Contact::Form.new(params[:contact_form])
if @contact_form.valid?
Contact::Mailer.contact_us(@contact_form).deliver
redirect_to :back, :notice => 'Thank you! Your email has been sent.'
else
render :new
end
end
end
end
but what seemed to be the final piece was @nathanvda's suggestions to move the contacts_controller from:
/app/controllers/contacts_controller.rb
to
/app/controllers/contact/contacts_controller.rb
Thank you both for your help!
精彩评论