How to give option for multiple templates for one view? - ruby-on-rails-3

I have an application in rails3 where i want to give user an option to choose a template from defaults (4 or 5 templates) to view his records.
the approach i am working on is to sent user on setting page from where he will select the template he want to use and on the basis of that setting the template will be rendered.
This looks simple but i am not sure this will work for me, please suggest me any alternative.
Please note i am talking about PDF formats.

Let's say you have a Setting model with a string attribute template.
You would let the user save the setting through a normal controller action.
Then on the controller where you want your pdf template to show, you could do something like this.
class MyController < ApplicationController
def show
#setting = Setting.find(params[:setting_id]) # Retrieve the setting instance
respond_to do |format|
format.pdf { render setting.template }
end
end
end
This will render the template named after the template the user has selected and is stored on setting as a string.

Related

rails render form after error in other controller

I have two models in the following releationship: Client has_many products, and Product belong_to client. In the client show view I present a form to create new products, that automatically belong to the current client. The show method in the client controller
def show
#client = Client.find(params[:id])
#products = #client.products.paginate(page: params[:page])
#product = #client.products.new
#product.client_id = #client.id
end
and the show view renders a partial
<h1>New Product:</h1>
<%= render 'shared/product_form' %>
That works, products are correctly created.
When an validation error occurs I set a flash in the product create method and redirect_to the client show page. There I loose the data that has been filled in correctly. I tried save the #product instance variable, which has all the data (including the wrong fields) doing
render client_path(client)
from the product controller, but that produces an error
Missing template /clients/17
with the address being
http://localhost:3000/products
Am I calling this wrong? I know that render ususally renders action of the same controller. Can I somehow render Client::show from the product controller? Is there another way to save the data the user has typed in?
If a validation error occurs you should redirect back to the page that generated the validation error. Ie: if the user is at products/new when they submit the form, then your products#create action should end with render :new to present the products form again.
If your products#create action is receiving the form from clients#show, then you do want to render clients#show with validation errors. In that case, all the information that was completed in the form will be available at params[:product], just like it is coming in to products#create.
You might want to take a look at another answer I wrote recently to understand the flow between controllers.
Specifically, the misunderstanding in your case is as follows:
When you have a validation error the record will not save, so you cannot "go back to that data" because your app has not kept it anywhere. The only copy of the data that was submitted is in the request.
If you REDIRECT you are not forwarding a request, you are responding to the initial POST request (which includes all the form information as params[:product]) by making a new request to a different url. This is why you want to use RENDER.
However, if you try to render clients_path(client), what happens is Ruby will first evaluate clients_path(client) to the string clients/(client.id), or in the example you gave, clients/17.
Then render tries to call render 'clients/17', which you don't have a template for. It's looking for a file called clients/17.html.erb. That's why you get the error you're getting.
So, again, to sum up - your products#create action receives the information that was sent from the form as params[:products]. That information is not available outside of this controller action. So, if there is a validation error, instead of creating the product, this controller action should render the same page that the user came from originally (normally products/new) so that they can see the form they just had (with the information filled back into it if you're using a form builder) and also see the error that prevented saving.
I hope that makes sense, feel free to ask follow-up questions.
Yes, you were calling it wrong.
There are three problems:
render should render a template name, say client/new, shared/form etc. The argument could not be a path or variable. The variable is passed by controller to view, nothing to do with render.
You should not use render for a saving fail. Even if you use a template name as #1 mentioned, you'll end up with a wrong URL like products/create with the client page. That's not acceptable.
My suggestion is to always use redirect for saving fail.
Minor problem. In controller, if you've used #product = #client.products.new, the #product object will have every attributes empty but with a valid client id. So you don't need to assign client id again by #product.client_id = #client.id. But this doesn't hurt the result.
Andrew's great answer plus this:
Where to render comments controller in Rails on model validations failure?
makes the solution more clear.
Your specific example: Just watch out that your create action in the ProductsController has all instance variables it needs to render 'clients/show' from it.

How to show one model in two different layouts?

I have two layouts: admin_layout.html.erb and application.html.erb. The admin works in the admin_layout and creates Users. There is a show page for each User under the admin_layout. But now I would like the general public to view a public version of each User's show page under the application layout. Is it possible to display two different show actions depending on the layout or do I need to build something like a public_users_controller?
You can specify which layout to use in your action, and you can also tell it to render a different template than the current action's name. In this example, public users would be shown the app/views/users/public_show.html.erb file using the app/views/layouts/application.html.erb layout.
def show
if current_user.admin? # Or however you want to determine which layout to use
render :layout => "admin_layout"
else
render "public_show", :layout => "application"
end
end

Render a partial instead or in a flash notice

I'd like to render a partial or similar in lieu of a simple flash notice. This is how it exists currently:
format.html { redirect_to share_url(#doc), notice: "#{#doc.title} has been created. You may #{view_context.link_to('edit', edit_doc_url(#doc))} it further, #{view_context.link_to('finalise', lock_doc_url(#doc))} it, or return #{view_context.link_to('home', root_url)}.".html_safe }
I'd like to render a partial or similar instead of the notice so I can customise it more.
Any thoughts? Thanks!
You could probably do it this way:
format.html { render action: "my_error_messages" }
Then create a my_error_messages action inside the same controller and create a corresponding view and route for it. Then customize the html/haml as you'd like.
Another approach might be to customize the messages partial for your flash messages which is most likely being called within your application layout. You'd likely find it in your apps/views/layouts directory.

Devise: Load a partial instead of showing a notice for non confirmed members

Is there a way to load a view for no confirmed users that login?
Default behaviour is to show a notice: " You have to confirm your account before continuing."
I tried
overrule the sessions#create method of devise checking for current_user.confirmed_at.blank?
in the after_singin_path check for current_user.confirmed_at.blank? and render the view instead
My goal is to render a custom view instead of the notice but cannot hook into the right location. Who knows how to accomplish this? thx!
You can simply copy the code from the devise github and place in your controllers/devise. then change any action or method you want to.
You may also just extend the devise session controller and override any action you want to.
class Abc < Devise::SessionsController
# this just reopens the class.
# Remember classes are never "closed" in ruby!
end
I like the ruby way of solving this, I guess that in your UsersController after a POST request the user will be returned and signed in using the sign_in(Object) helper Devise provides.
Also I suggest using a confirmed boolean instead of timestamp.
Why not check for the value using an if else statement the ruby way:
user.confirmed ? sign_in(user) : render :partial => 'path/partial'
Hope this might help you out

Render a page as a saved HTML file using Rails 3.0?

I'm building a simple website generator application in Rails 3.0. I'd like a "publish" action in a controller that works just like an ordinary "show" action, but instead, saves a page as an HTML file in the "public" directory instead of displaying it in the browser. That is, I'd like to use the Rails render mechanism to create a file instead of providing an HTTP response.
What's the best way to do this?
Should I simply add caches_page :publish to the controller?
Or use render_to_string and File.new?
You can use render_to_string method: http://apidock.com/rails/AbstractController/Rendering/render_to_string
You still need to respond from the controller though. Maybe redirect to the page you just saved?
I would go with page caching.
Then if you have editable content, the pages should be automatically generated. You could then write a system task which bundles them up as a web site.
see (whatever)/actionpack/lib/action_controller/caching/pages.rb for instructions.
I found that page caching using caches_page won't work for me because there is no way to show a notification or redirect to another page after caching the page. The method render_to_string (suggested by #Grocery) is the way to go. Here's the example controller code:
def publish
#article = Article.find(params[:id])
html = render_to_string(:template => "articles/template.html.haml", :layout => 'article' )
FileUtils.makedirs("#{Rails.root}/public/articles/") unless File.exists?("#{Rails.root}/public/articles/")
File.open("#{Rails.root}/public/articles/#{#article.filename}.html", 'w') {|f| f.write(html) }
respond_to do |format|
format.html # publish.html.erb
end
end