I wanted to set layout to my Devise sign-in page, so I added the following to my ApplicationController:
class ApplicationController < ActionController::Base
protect_from_forgery
if devise_controller?
layout "single_column_with_banner"
end
end
However, I get the following error:
undefined method `devise_controller?' for ApplicationController:Class
I can see that the helper method is specified in devise.rb, but I just can't access it from application controller. I'm using Rails 3.2 (in process of migration from 2.3). Any clues where I should look at? As a last resort I can override SessionsController but I don't really want to do that yet.
It seems like layout can be specified without either device_controller? or overriding SessionsController. In order to specify layouts, place the following in application.rb:
config.to_prepare do
Devise::SessionsController.layout "single_column_with_banner"
end
Related
Devise has a handy feature called devise_group (link to documentation), which creates a group with your multiple devise models.
The docs are really self explanatory. If you have 2 devise models named, for instance, Admin and User, you can use devise_group like so:
class ApplicationController < ActionController::Base
devise_group :blogger, contains: [:user, :admin]
end
This would give you, alongside with authenticate_user! and authenticate_admin!, the method authenticate_blogger!, which would redirect unless user or admin were signed in.
We have been using this in production and it works great. We have the flexibility to restrict some Controller/actions to admins using authenticate_admin! and use authenticate_blogger! when we can have both accessing it.
Due to some complex business logic we have, we had to override authenticate_user! in ApplicationController, following this nice StackOverflow answer here.
Basically it proposes to override ApplicationController#authenticate_user! and calling super when we want the flow follow trough Devise's.
The problem arose when we tried to do the same solution with `authenticate_blogger!. If we do this:
class ApplicationController < ActionController::Base
devise_group :blogger, contains: [:user, :admin]
def authenticate_blogger!
super
end
end
// Another controller
class DashboardController < ApplicationController
before_action :authenticate_blogger!
end
Rails raises this error:
super: no superclass method `authenticate_blogger!' for #<DashboardController:0x00007fd453ca5d80> Did you mean? authenticate_user!
Any idea why calling super inside an override of authenticate_user! in ApplicationController works fine, but the same doesn't happen with the devise group equivalent ?
EDIT 1: found out the reason, but could use some help improving the solution
Looking at devise source code, devise_group uses Ruby's class_eval do define instance methods like authenticate_blogger! in the context of the class it was called.
So when we use devise_group inside ApplicationController, it's like we're defining authenticate_blogger! as an instance method in ApplicationController.
That's why when we manually define that method authenticate_blogger! in ApplicationController and call super it raises the exception, because we actually overwrote the same instance method in the same class (ApplicationController) and there's nothing to find up in the ancestor chain.
authenticate_user!, on the other hand, is way up in the ancestor chain in Devise::Controllers::Helpers (I can see it calling ApplicationController.ancestors`.
The hacky-proof-of-concept-fix we did was to create a TempController, define devise_group inside it, and make ApplicationController inherit from it:
class TempController < ActionController::Base
devise_group :advertiser, contains: [:user, :broker]
end
// In application_controller.rb
class ApplicationController < TempController
def authenticate_blogger!
super // this now works since it goes up in the ancestor chain and finds authenticate_blogger in TempController
end
end
Even tough I'm happy with my investigation ... any suggestions on fixing this without actually having to make ApplicationController not inherit ActionController::Base, like it's default in Rails?
Using a namespaced controller and the app's Application layout isn't being loaded.
# controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
end
# controllers/servers/base_controller.rb
module Servers
class BaseController < ApplicationController
def initialize
# I noticed params are not accessible here either...
# Only in the child controller.
end
end
end
# controllers/servers/test_controller.rb
module Servers
class TestController < BaseController
def index
end
end
end
A pretty basic setup here. Anytime I route to /servers/:id it loads the page with the parameter, but the application layout does not load. I have a series of a couple controllers I'd like to all inherit from this BaseController to initialize a few things. I also noticed that besides the layout issue, the BaseController doesn't have access to url parameters. The TestController does though... Can anyone explain these two issues I'm seeing?
Rails 5.1.4
ruby 2.4.1p111
Figured out my issue. Don't use an initialize method in your class. Rails doesn't like that. Use before_action instead.
I'm having trouble accessing a helper method after upgrading to Rails 4.1.1. I have the following code in my application.
module ApplicationHelper
def last_page_url
session[:last_page]
end
end
class Admin::ArticlesController < ApplicationController
def update
#....more code here
return redirect_to self.last_page_url
end
end
In Rails 4.0.x this code worked fine. After upgrading to Rails 4.1.1 I'm getting an error "undefined method 'last_page_url' whenever my update action runs. Why is this breaking now?
I'm not really sure why this stopped working after upgrading to Rails 4.1.1, but as #steel suggested, it had something to do with the helper method not being included in my particular controller. Adding include ApplicationHelper to the top of my Controller would have worked and I probably could have taken it a step further by adding it to the ApplicationController class since I needed that method available to all controllers. In the end I opted for a different solution:
First, I moved the last_page_url from the ApplicationHelper to the ApplicationController class so all of my controllers could access it. Then I used helper_method to make this method available to all my views. My final code is as follows:
module ApplicationHelper
end
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
def last_page_url
session[:last_page]
end
helper_method :last_page_url
end
If anyone ever figures out something changed from Rails 4.0 to Rails 4.1 I would be interested in learning what happened. In this particular application I'm just using the default Rails 4.1 settings in my development.rb.
Inside my helper/posts_helper.rb file, I'm defining a method such like this:
module PostsHelper
def testing(test)
"Yep its a #{test}"
end
end
I assume that this testing helper should work only inside my posts views. But it works at all of my views, even views of other resources of my application. I'm not putting this in application_helper.rb. How come it happens?
Here is my application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
end
It is a common misconception that Rails will only load the helpers for a specific controller. By default, Rails will load all helpers. You need to set this line in your application.rb:
config.action_controller.include_all_helpers = false
This will only load the helpers that you expect (the one for your controller and anything in it's inheritance chain, such as ApplicationHelper etc).
Check for helper :all somewhere, such as your application controller.
Fist of all I'm newbie to rails.
I have this in SessionsController:
def method
sign_in 'user'
end
And this in SessionsHelper:
def sing_in(user)
......
end
So Googling and reading some answers on stackoverflow let me to try something like this:
Including the 'SessionsHelper' to the SessionsController and even tried to put it in 'ApplicationController' like this:
class ApplicationController < ActionController::Base
protect_from_forgery
include SessionsHelper
def handle_unverified_requests
sign_out
super
end
end
But I'm getting
NoMethodError : undefined method `sign_in' for SessionsController:0x007eff2004fcd8
Also few questions:
1) What's the point/difference in putting few methods in Heplers and few in Controllers? Is it a security issue or what?
2) I also tried puting the sign_in method in the SessionsController as i read in stackoverflow that methods defined in controllers can be accessed in views. so to avoid any problems in the views I used
helper_method
but still the same NoMethodError
3) THe best and easy way to access the helper methods in controllers?
So where am I going wrong.
I'm using Rails 3.2.11 and Ruby 2.0.0p0
Looks like a typo: your helper method is 'sing_in' instead of 'sign_in'.