My app has a modal sign in form that I display using ajax:
<% if !current_user %>
<%= link_to "Sign in", signin_path, remote: true %>
<% end %>
routes.rb
get 'signin', to: 'static_pages#signin', as: 'signin'
static_pages_controller.rb
def signin
respond_to do |format|
format.html { render :action => 'signin.js.erb' }
format.js { render :action => 'signin.js.erb' }
end
end
signin.js.erb
$('#modalPlaceholder').html("<%= j render(partial: '/static_pages/signin') %>");
$('#modalPlaceholder').show();
This works well.
I would now like to intercept actions that require user sign in and display this modal. In my application controller I have:
application_controller.rb
def require_signin!
if current_user.nil?
render :action => '../static_pages/signin.js.erb'
end
end
helper_method :require_signin!
This works when the originating action is remote: :true and rails simply redirects it however when the originating action is a standard request the action is intercepted correctly by the application controller however the modal is displayed on screen in raw html and not loaded correctly.
You can check format type of request and render for it.
def require_signin!
if current_user.nil?
if request.format.html?
#html render file here
else
render :action => '../static_pages/signin.js.erb'
end
end
end
Related
I'm having trouble rendering a particle on a button click. I'm getting the error
HelpController#FAQ_help is missing a template for this request format
and variant. request.formats: ["text/html"] request.variant: []
main_page.html.erb
<%= link_to "FAQ", FAQ_help_path %>
<div id="content">
</div>
help_controller.rb
def FAQ_help
respond_to do |format|
format.html {}
format.js
end
end
FAQ_help.js.erb
$('#content').html("<%= render :partial => 'FAQ_help' %>");
_FAQ_help.html.erb
<div>
<h1> This is the FAQ </h1>
</div>
routes.rb
get 'FAQ_help', to: 'help#FAQ_help'
How about this:
# main_page.html.erb
<%= link_to "FAQ", FAQ_help_path, remote: true %>
And
# faq_help.js.erb
$('#content').html("<%= escape_javascript(render :partial => 'FAQ_help')%>")
#fixed syntax
Cheers!
Since you have created a method for this request I would define it a little more for clarity:
def FAQ_help
respond_to do |format|
format.html {}
format.js {render: FAQ_help}
end
end
If you want to keep your controllers clean I would pass a param with the link and check if the pram is present if it is render FAQ partial:
View:
<link_to "Your FAQ" your_path, data: {method: :get, :remote => true, params: { faq: "#{current.user_name}" }.to_param }, :class =>"button" %>
Controller:
if params[:faq].present?
respond_to do |format|
format.html {}
format.js {render: FAQ_help}
end
else
respond_to do |format|
format.html {}
format.js {} #your default view for this method
end
end
This is handy to display IE:different content as per the request
ie: parms =bob # displays bobs FAQ
ie: parms =ted # displays teds FAQ
This technique is similar to what you would implement to create a search.
When the user is not signed in, it shows "You need to sign in or sign up before continuing" when after he's tried to execute the actions which need authentication.
That's just how I want it so it's okay.
However, the problem is that, it takes user to the blank page(which is ajax requested url so it's blank) when after he signed in.
Is it possible to let him stay at the same previous page, and just let it execute ajax request with remote=>true?
How can I handle this kind of problem?
[UPDATE]
users_controller.rb
before_filter :authenticate_user!, :only => [:follow, :unfollow]
def follow
#user = User.find_by_username(params[:id])
current_user.follow(#user)
respond_to do |format|
format.js {render :action=>"follow.js"}
end
end
view
<% if current_user.following?(user) %>
<%= link_to(unfollow_user_path(user), :remote => true) do %>
Following
<% end %>
<% else %>
<%= link_to(follow_user_path(user) ,:remote => true) do %>
Follow
<%end%>
<% end %>
when the user is not logged in and executes a request he is forced to sign in, when he successfully sign in he is redirected to previous page, i.e. redirect_to :back, but when he executes an ajax request, there is no html page that renders ajax action(def follow).
def follow
#user = User.find_by_username(params[:id])
current_user.follow(#user)
if request.xhr? # ajax request
respond_to do |format|
format.js {render :action=>"follow.js"}
end
else
redirect_to home_path # or any other path
end
end
I am using Authlogic gem for user sessions.
The login form is shown in a modal, so if the user credentials are incorrect, I want to display the error message on the modal, thats why I use remote: true.
<%= form_for #user_session, url: user_session_path, ***remote: true do |f| %>
I want to respond_to format.js when the user_session had errors, and redirect_back_or_default root_path when user_session is saved correctly
The problem I am having, is that if the credentials are correct, the page is not redirected.
Here is a screenshot of the resulting requests for a request with proper credentials:
user_sessions_controller.rb
class UserSessionsController < ApplicationController
before_filter :require_no_user, :only => [:new, :create]
before_filter :require_user, :only => :destroy
def new
#user_session = UserSession.new
if #user_session.save
redirect_back_or_default root_path
else
format.js
end
end
def create
#user_session = UserSession.new(params[:user_session])
if #user_session.save
flash[:notice] = "Login successful!"
redirect_back_or_default root_path
else
render :action => :new
end
end
def destroy
current_user_session.destroy
flash[:notice] = "Logout successful!"
redirect_to authentications_path
end
end
new.js.erb
(function($){
<% if #user_session.errors.any? %>
$errorsContainer = $("#login-errors").empty();
<% #user_session.errors.full_messages.each do |msg| %>
$errorsContainer.append('<div class="alert alert-error"><%= msg %></div>');
<% end %>
<% end %>
})(jQuery)
Try the following hack instead of redirect:
render :js => "window.location = '/index/'"
replace /index with whatever your root url is. It seems Rails is looking for javascript type response for both cases since you used ajax
I have an issue where I think I need to use both a redirect and a render within the same action and I keep getting the double render error so I wondered if anyone could see another way.
I have a form with a select box and a button that allows users to choose from a set of cities to navigate to.
<%= form_tag root_path, :method => :post do %>
<%= select_tag :city, options_for_select(%w{ Pittsburgh Philadelphia Austin }) %>
<%= submit_tag "Change City" %>
<% end %>
and in the controller, I check for the city parameters then redirect to the desired page.
def index
if params[:city] == "Pittsburgh"
redirect_to pittsburgh_path
elsif params[:city] == "Philadelphia"
redirect_to philadelphia_path
elsif params[:city] == "Austin"
redirect_to austin_path
end
render :layout => false
end
But on this page I've created a specific layout/design which is only on that page so I just turned off the application layout.
Can I perform the navigation actions and turn off the rendering of the application layout at the same time?
Yes, move the checks in a before_filter.
class MyController < ApplicationController
before_filter :redirect_customized_cities, :only => :index
def index
render :layout => false
end
protected
def redirect_customized_cities
case params[:city]
when "Pittsburgh"
redirect_to pittsburgh_path
when "Philadelphia"
redirect_to philadelphia_path
when "Austin"
redirect_to austin_path
end
end
end
Or you can do a return statement after any redirect; like returning true or false after the redirect will halt the method chain.
I am building a fairly simple recipe app to learn RoR, and I am attempting to allow a user to save a recipe by clicking a link rather than through a form, so I am connecting the user_recipe controllers 'create' function through a link_to.
Unfortunately, for some reason the link_to is calling the index function rather than the create.
I've written the link_to as
<%= "save this recipe", :action => 'create', :recipe_id => #recipe %>
this link is on the user_recipes/index.html.erb and is calling the 'create' function of the same controller. It doesn't seem to make a difference if I include the :controller or not.
The controllers look like this
def index
#recipe = params[:recipe_id]
#user_recipes = UserRecipes.all # change to find when more than one user in db
respond_to do |format|
format.html #index.html.erb
format.xml { render :xml => #recipes }
end
end
def create
#user_recipe = UserRecipe.new
#user_recipe.recipe_id = params[:recipe_id]
#user_recipe.user_id = current_user
respond_to do |format|
if #menu_recipe.save
format.html { redirect_to(r, :notice => 'Menu was successfully created.') }
format.xml { render :xml => #menu, :status => :created, :location => #menu }
else
format.html { render :action => "new" }
format.xml { render :xml => #menu.errors, :status => :unprocessable_entity }
end
end
In the standard REST scheme the index action and the create action both have the same url (/recipes) and only differ in that index is accessed using GET and create is accessed using POST. So link_to :action => :create will simply generate a link to /recipes which will cause the browser to perform a GET request for /recipes when clicked and thus invoke the index action.
To invoke the create action use link_to {:action => :create}, :method => :post, telling link_to explicitly that you want a post request, or use a form with a submit button rather than a link.
Assuming you have default resources set up in your routes file, i.e. something like this
resources :recipes
The following will generate a link that will create a recipe; i.e. will be routed to the create action.
<%= link_to "Create Recipe", recipes_path, :method => :post %>
For this to work, JS needs to be enabled in your browser.
The following will generate a link that will show all recipes; i.e. will be routed to the index action.
<%= link_to "All Recipes", recipes_path %>
This assumes the default which is a Get HTTP request.