Multiple buttons pointing to single Controller Action - ruby-on-rails

I am making an app where user can print a doc in either PDF or JPG format, using wicked-pdf and imgkit respectively.
I have two buttons, one for PDF and other JPG. Is it possible to have these buttons point to same action in controller which here is 'create'.
my buttons are as-
<%= button_to "Print Bill[PDF]", :action => "create" %>
<%= button_to "Print Bill[JPG]", :action => "new" %>
can i make both the actions create?
if yes, how so? How to catch which button is hit and render the respective view.

First of all, it is generally recommended to use route helpers, rather than specify controllers and actions. So your code could be
<%= button_to "Print Bill[PDF]", bill_print_path(#bill, format: :pdf) %>
<%= button_to "Print Bill[JPG]", bill_print_path(#bill, format: :jpeg) %>
and in your controller
def print
# insert here code to find your bill and load it from DB
respond_to |format| do
format.jpeg do
# code to produce the jpeg version of the bill
end
format.pdf do
# code to produce the pdf version of the bill
end
end
end
As a final step I would change button_to to link_to and style your link as a button, but that is more of a personal preference.

Related

Render custom edit partial in a 'Custom Page' in ActiveAdmin

I'm using ActiveAdmin for a project. I have and I have a partial with a custom form. I want to be able to render this custom form when the user clicks in a button so this is what I did:
ActiveAdmin.register_page "Messages" do
menu priority: 5
welcome_message = Template.first
page_action :update, method: :put do
#update code
end
page_action :edit, :method => :get do
render partial:'custom_form', locals: { settings: welcome_message }
end
action_item do
link_to "Edit", admin_welcome_messages_edit_path, :method => :get
end
content do
render text: "HI"
end
end
This works, but the problem is that my form gets rendered without the layout and styles of ActiveAdmin, it just shows my custom_form as a clean html.
If I render my custom_form in the content do ... end it does work, but I need that to show something different.
Any help?? I don't know what else to try, I have reached the first 3 pages of google without success!!
kind of an old question but I was having the same problem and this solved it for me.
render partial: "name_of_your_partial", layout: "active_admin"
wasn't working for me either so I just changed my partial into a template.
render: "name_of_your_template", layout: "active_admin"
and now the activeadmin layout is being displayed.
I did not find an answer for this but I found a nice workaround that looks pretty good.
In the action_itemI have a link to admin_welcome_messages_path that is the main view and if I'm editing add a param there to show the form instead of the body.
Hope it helps somebody!
ActiveAdmin.register_page "Messages" do
menu priority: 5
welcome_message = Template.first
page_action :update, method: :put do
#update code
end
action_item do
link_to "Edit", admin_welcome_messages_path(edit: true), :method => :get
end
content do
if params["edit"] == "true"
render partial:'form', locals: { settings: welcome_message }
else
render partial:'body'
end
end
end
Add layout option to the render call.
render partial:'custom_form', layout: 'active_admin', locals: { settings: welcome_message }
Determine which layout to use.
If we're rendering a standard Active Admin action, we want layout(false)
because these actions are subclasses of the Base page (which implements
all the required layout code)
If we're rendering a custom action, we'll use the active_admin layout so
that users can render any template inside Active Admin.
https://github.com/activeadmin/activeadmin/commit/ce0927661c5991cc857306363c402ef9e283cc42
# this would automatically render the custom_edit.html.erb view
page_action :custom_edit do
end
action_item do
link_to "Custom Edit", admin_welcome_messages_custom_edit_path
end
I realise that this an old question but the following worked for me for my Ruby on Rails application:
Inside your your_custom_page.rb file do the following
content do
render 'partial_name'
end
and place the _partial_name.erb in view/admin/your_custom_page/
Your partial should now render on that active admin page.

Ruby on rails "no route matches" when trying to use a separate controller

So I'm currently trying to map my building's network with a RoR implementation. I have a good floor plan set up, and I've created the switch objects for it as well. Eventually, the switches will have many jacks, and each jack will map one-to-one with a room number.
Currently everything is working perfectly through the floors and switches until I try to show the switch individually. I'm trying to do this by using the show method in a separate controller. Originally the floor controller was in charge, but now I want the switch controller to be.
Here is my partial switch code (apps/views/switch/_switch.html.erb):
<p>
<%= switch.title %>
<%= link_to 'show', :controller => "switches", :action => 'show' %>
<%= link_to 'Destroy', [switch.floor, switch],
:confirm => 'Are you sure?',
:method => :delete %>
</p>
Here is my show method (apps/controllers/switches_controller.rb):
...
def show
#floor = Floor.find(params[:floor_id])
#switch = #floor.switches.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #switch }
end
end
...
When I do not tag the switch controller in the partial, whenever I click show the link acts as a link back to the same page...basically just a refresh. When I do tag the switch controller I get the ' No route matches [GET] "/assets" ' error.
I've tried MULTIPLE different syntaxes and nothing has worked. If anyone can help me out I will be very thankful!!
Please let me know if it's necessary to post more of my code and I will.
You can run 'rake routes' command to list all available routing options and recommend you to use url/path rather than specifying controller and actions for individual links.
I assume that you have setup nested route for floor and switch, then to obtain this URL i.e
/floors/:floor_id/switches/:id/show
you can use
<%= link_to "Switch", floor_switch_path(switch.floor, switch) %>
'Show' method used to display particular element. Particular switch in your case. So you need to send :id to your controller, like this
link_to "Switch", :controller => "switches", :action => "show", :id => switch

Ruby on Rails form_remote_tag missing template

I'm using form_remote_tag(:url => {:controller => "home", :action => "search"}, :update => "mydiv"). When I click submit on the form "mydiv" is populated with the error "Template is missing. Missing template home/search.erb in view path app/views". I've tried multiple render options in def search, but they all result in the same error.
It looks like the search method is trying to use it's default render even though I'm specifying what I want.
I've tried:
render 'index'
render :text => 'Return this from my method!'
Is my url incorrect? Is it not submitting back to my home controller's search method?
Try
render :action => 'index'
this will use "index.rhtml" or "index.html.erb".
I will try to explain why it said search.erb is not found, lets take create action for a some model, if there is some error in my create action they it will throw missing template create.html.erb file, since you have some error in your create action rails will try to render the create.html.erb in the page. Hope I explained it clearly.
In an ajax action you can't use redirect_to or render options directly.
try using this in your search action
render :update do |page|
page.replace_html "ur_div_id","partial"
end
The form_remote_tag needs prototype to function. Make sure you are including the :defaults for your javascript libraries namely prototype.
<%= javascript_include_tag :defaults %>

Prompt a user to login after he takes a certain action

One thing you can do on my rap lyric explanation site is "like" explanations (once you're logged in):
http://dl.getdropbox.com/u/2792776/screenshots/2010-01-17_1645.png
I'd like to show the "Like" links to users who aren't logged in, and then, when a non-logged in user clicks "Like", show him a lightbox with a "Login or Register" form (like Digg / Reddit)
http://dl.getdropbox.com/u/2792776/screenshots/2010-01-17_1650.png
What's the best way to accomplish this?
Currently I'm using this approach:
Clicking "Like" POSTs to /annotations/:id/vote (the POST body indicates whether the user is liking or "unliking").
The vote Annotation controller action has a require_user before_filter that looks like this:
def require_user
unless current_user
store_desired_location
flash[:notice] = "You'll need to login or register to do that"
redirect_to login_path # map.login '/login', :controller => 'user_sessions', :action => 'new'
return false
end
end
user_sessions#new looks like this:
def new
#user_session = UserSession.new
respond_to do |format|
format.html {}
format.js {
render :layout => false
}
end
end
The problem is that the redirect doesn't seem to work correctly over javascript:
http://dl.getdropbox.com/u/2792776/screenshots/2010-01-17_1700.png
How do I get this to redirect correctly?
Also, is this the right general approach? Another thought I had was to attach a different handler to the "Like" links in javascript when there was no logged in user (but I don't think this method scales well to other actions that I'd like to handle the same way)
There's a few problems to overcome here.
Browsers in general do not allow redirecting to a POST request.
redirect_to doesn't preserve format without additional input.
Store location does not preserve form data.
All these problems can be solved by eliminating redirects.
Here is how I've handed it in the past:
Instead of redirecting in required_user, render. If a before filter redirects or renders the pending action is cancelled. (No need to return false either). Unfortunately going this route blurs controller boundaries. But allows for simple html fallback, and lends its self to DRYness.
The high level view of the new work flow will be:
Request to annotations#vote (POST)
required_user filter fails
render new session
submit login information and original POST data back to annotations#vote (POST)
new filter in vote captures session information and logs in. vote proceeds as expected. If login fails return to 3.
annotations#vote redirects/renders as it should
Start by reworking the require_user to render the user_sessions#new template.
def require_user
unless current_user
flash[:notice] = "You'll need to login or register to do that"
#user_session ||= UserSession.new
respond_to do |format|
format.html {render :template => 'user_sessions/new'}
format.js {
render :template => 'user_sessions/new', :layout => false
}
end
end
end
The #user_session ||= UserSession.new ensures we can return validation errors to the form.
Now we've got to beef up your user_session#new template so that it can remember the action. Also if you plan on using lightboxes, this should be a partial rendered rendered by relevant RJS or the new.html.erb.
First we create a partial to create hidden fields preserving the POST data that would have been lost in a redirect:
<% if params[:controller] == "annotations" %>
<% content_for :old_form do %>
<%= hidden_field_tag "annotation[song_id]", params[:annotation][:song_id] %>
<%= hidden_field_tag "annotation[vote]", params[:annotation][:vote] %>
<% end %>
<% end %>
Then render that partial in the login partial that will occupy your lightbox:
<%= render :partial => vote_form_replica %>
<% url = params[:controller] == "user_sessions ? user_sessions_url : {} %>
<% form_tag #user_session, :url => url do |f| %>
<%= yield :old_form %>
<%= f.label :user_name %>
<%= f.text_field :user_name %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= submit_tag %>
<%end%>
The empty hash for url in the form_tag looks like an error, but isn't. It ensures that the form data is posted to the url that rendered the form. Which at this point should be annotations/:id/vote
Now for the new filter to login. Essentially it will be doing what ever UserSessionsController#create does without the render/redirect. The following is copied from the RESTful authentication plugin.
def authenticate
self.current_user = User.authenticate(params[:login], params[:password])
if logged_in?
if params[:remember_me] == "1"
current_user.remember_me unless current_user.remember_token?
cookies[:auth_token] = { :value => self.current_user.remember_token,
:expires => self.current_user.remember_token_expires_at }
end
end
end
All that's left is to make sure the filter order is right.
before_filter :authenticate, :require_user, :only => :vote
N.B.: You're probably not going to use this version of require_user without this version of authenticate so it makes sense to combine them into a single filter.
And that's it. The way this has been set up allows for robust DRY easily reuseable code. By placing the new filters into ApplicationController they're available in any controller. From this point, adding this functionality to any other controllers/actions takes only 3 simple steps:
Create a new partial modelled after the vote_form_replica partial.
Add the corresponding render statement to the new session template.
Apply the filters to your actions.
I would approach this in the way you describe at the bottom of your question. Before displaying the page initially, check if the user is logged in. If they are, the "Like" links should use their normal behavior. If not, bind a click event to show the register/login panel. There's nothing about this that can't be reused. In fact, we use this exact method at my job. Any user action that requires authentication either follows its normal behavior or pops up a generic login panel depending on login state at the time the page loads.

Rails RESTful controller and rendering after custom action

How can I render after executing an action in a restful controller instead of redirecting.
I have a controller with standard actions, and I added a special action that adds data to the resource in question, via a form on the #show page (Think comments on a post). I am validating the input from the form and want to re-render the show action on error and redirect to the show action on success.
I want to render to save the user from inputting their info twice, but when I try to render the show action with an error in the flash[:notice] I get an error saying that I am not specifying an ID. When I do specify an ID, it tries to render a new template that doesn't exist yet.
I am thinking that it should be a as simple as:
def add_comment
if my_validation?
save the object
redirect_to :action => "show", :id => params[:id]
else
render :action => "show", :id => params[:id]
end
end
This is not my actual code, just something I put together just now as an example.
The best way is to re-render the :new
def create
#obj = TheObject.new(params[:object])
render :action => :new unless #obj.save
end
And in the new.html.erb
<% form_for :obj,
:url => object_url(#obj), :html => {:method => :post} do |f| %>
<%= f.text_field :name %>
<% end %>
That way, the inputs in the form will be pre-filled with what the user entered.
Create a new data object and add the values from the form, before you rerender, think it would work then. If you still get problems, try setting a boolean for editing new vs. existing rows, or create two different views entirely.
I've done it before but I don't quite remember how. Sometimes when I used the very typical use of the MVC pattern, it was allmost "automagical", othertimes (as I had to use an old quirky database) I had to code all the magic myself; sometimes usin the .new? function (or what it was called) on the ActiveRecord object, othertimes I used temporary "magic values" for ID (typically alphabetic strings for invalid id values.
(I appologize if I made some mistakes, it's a while since I coded Rails code...)

Resources