Login form as popup modalbox (only the rails part)

While redesigning an existing application, I've stumbled on a problem.

A number of links on the site requires that the user logs in. This is currently solved by the simple (example)

<%=link_to 'Upload image', :controller => 'image', :action => 'new' %>

and in the ImageController I place a

before_filter :login_required, :only => :new

(login_required checks the session userdata, and redirects to a login-page if necessary)

I want to change it at bit, so that when the user clicks the link - and a login is actually required - a modalbox popup containing a login form pops up _on the same page as where the user clicked on the link_

My issue is how to detect if the controller/action requires a login?

I am working on the concept to do something like this in the view

<%=protected_link_to 'Upload image', :controller => 'image', :action => 'new' %>

and in the helper:

def protected_link_to(caption, options = {}, html_options = {})   if <options requires a login>     var url = url_for(options)     return link_to_function caption, "show_login_popup(...blabla..., {continue_url: url});"   end

  return link_to caption, options, html_options end

Question is: How do I implement the if <options requires a login>

Thanks

- Carsten

My issue is how to detect if the controller/action requires a login?

I think you’re going to have a fair bit of monkeying around to do.

A hint in the right direction is you can do this:

controller = “#{options[:controller]}_controller”.camelize.constantize

controller.filter_chain.map(&:method)

There’s probably a better way of doing step 1, in case you have namespaced controllers or something, but still.

Once you have the filter methods (from step 2) you can iterate over them and see if your login_required filter is present. You may have to do some more monkeying in the options in each of the objects returned by filter_chain to check for :only and :except options and handle those.

If you are linking to a URL rather than a :controller/:action pair you may want to use something like this in step 1:

controller_name = ActionController::Routing::Routes.recognize_path(path)[:controller]

Anyway, it’s going to be quite deep/tricky, but that may give you a nudge in the right direction. Post back if you need more help.

Cheers,

Andy

OK, so I had a bit more of a play. You’ll still need to do this:

controller = “#{options[:controller]}_controller”.camelize.constantize

But if you create a file in config/initializers called “action_filtered.rb” and put this in it:

class ActionController::Base

def self.action_filtered?(action_name, filter_name)

action_name = action_name.to_s

filter_chain.each do |filter|

if filter.method == filter_name

if filter.options[:only].respond_to?(:include?)

if filter.options[:only].include?(action_name)

return true

end

elsif filter.options[:except].respond_to?(:include?)

if !filter.options[:except].include?(action_name)

return true

end

else

return true

end

end

end

false

end

end

You’ll then have a method on a controller so you can do this:

controller = “#{options[:controller]}_controller”.camelize.constantize

login_required = controller.action_filtered?(options[:action], : login_required)

And login_required will be a boolean value as to whether the login_required filter is effective for that action.

You will probably want to wrap that up in to a method somewhere neater and you’d need to consider that the user may already be logged in (in which case you don’t want the popup), but it may help you get started.

Cheers,

Andy

Andy Jeffries wrote:

OK, so I had a bit more of a play. You'll still need to do this:

This (and the previous reply) is exactly what I needed! Thanks a bunch :slight_smile:

You will probably want to wrap that up in to a method somewhere neater and you'd need to consider that the user may already be logged in (in which case you don't want the popup), but it may help you get started.

Yes I am going to 1) put it into a helper 2) Let the routing configuration help to decipher controller and action name (since I have a mix of link_to calls with straight urls, controller/action hashes and rest routes) 3) Check for if the user is already logged in.

This is really great - you rock!

- Carsten