how to add a `preview` action to resources? - ruby-on-rails

I am looking for the right approach to include a preview action between new and create actions.
Let's assume I have the following:
resources :users
By default, when the form is submitted:
if new, call create action;
if edit, call update action.
In this way, I can use the same form (partial) for new and create, which is great!
How can I configure the resources to include a preview between actions. I mean, forcing new to call preview and then preview to call create.
I could add a new route/action and point the form for that action, however the same form cannot be used for new and edit.
There is a way to configure the resources to do that?

Have a look at this railscast: multibutton form, it shows a form with both a 'preview' and 'submit' button, maybe that's something you might want to do.
By the way, couldn't you use the same form by passing locals to the partial? For example:
<%= form_for #profile, url: dynamic_path do |f| %>
...
<% end %>
<%= render 'form', dynamic_path: profile_preview_path %>

you have several ways to do this:
you change the url of the form to your preview action (for which you have to add a route).
you use your create action for preview and create:
i.e. you add a parameter (like ':go_to_preview') to the form submit request. if you find it in the controller you render preview.
when the user wants to confirm the preview, you submit the data again (without that parameter) and this time create the record.
there are also 2 more dynamic possibilities:
you create the preview in real-time - if that is possible (like here on SO) - and use just the create action,
a variation of the first option: when the user submits the form, you send an ajax post request to a preview action, render a partial and include it on the page, then while your user still has the form he just filled, the user decides if she wants to modify or submit definitely.

I would suggest adding a DateTime column "finished_at", "published_on", etc... whatever is appropriate for your domain.
Using blog posts as an example:
scope :published, where("published_on IS NOT NULL")
scope :draft, where(:published_on => nil)
Use the scopes and new field where appropriate to limit the follow up actions.
This approach gives you more than you asked for :
a way to limit processing based on "state"
Data on creation times versus publishing times

Related

Passing param using link_to and UJS

I'm having a hard time understanding the proper way to pass a param using link_to and UJS.
I have the following resources:
Photos
Comments
Users
A user is trying to comment on a photo by clicking "Add Comment." When this happens a box pops up using UJS showing a form rendered by utilizing a new.js.erb file. After "Create Comment" is posted the create.js.erb file is called to handle the update, which just hides the comment box and adds the comment to a list of comments.
In my index.html.erb for my photos I am doing the following:
I specify a link to add comments passing in the id of the current photo.
<%= link_to 'Add Comment', new_comment_path( photo_id: photo.id ), remote: true %>
This gives me the url: 0.0.0.0:3000/comments/new?photo_id=1, which is what I expect.
Now my question is, how do I handle this passed parameter in my new action such that I can specify something like
#comment.photo_id = photo_id
or
#comment.photo_id = params[:photo_id]
in my comments_controller.rb?
Is there something I can do in JS that will help me save the photo_id value to my #comment.photo_id column for the comment added?
First of all I'll suggest you to start using nested routes for things like comments or likes. You will find the railscast here nested_routes_railscast
Coming back to your question, use #comment.photo_id = params[:photo_id] in your controller.
There is a better approach to accomplish this, You can have the popup already on the photo show page. In the popup you can have a form for new comment model. After clicking on the specific photo you just have get the id of that photo using javascript and copy it into the hidden field for :photo_id in the form.
Yes, you can get photo_id in params, they way you have specified.
Suppose Photo has many comments in your case.
So in your case when in you get params[:photo_id] in comments_controller
you can do:-
#photo = Photo.find_by_id(params[:photo_id])
#photo.comments.create(params[:comment])
Please read about nested resources from guides.rubyonrails.org, so you can generate create comments route in restful manner.

Rails form redirecting to 'new' action

What I am trying to do is build a form in which the user fills some of the fields for a new Publication, and takes you to the New Publication action, with those fields already filled in, so the user fills the rest.
I got the controller part covered, but I cant find how to use form_for for this, as its not exactly associated to the model (only some of the necessary fields are in the first form).
you could do
form_tag new_publication_path()
Not necessarily the best way to do this, but you can hide some of the fields in the form depending on whether the model id is valid. For example (in haml):
- if #model.id #only shows up if the model has been saved.
= f.text_field :field_name, ...
This way you can use the usual new, and then when the model has been saved, just redirect to the 'edit' action and the rest of the fields show up.

Drop down select ruby rails

Here's my code for a form that contains a drop down list -
<div class="field">
<%= f.label :type, "Select profile type"%>
<%=
f.select :type, Profile::TYPES,
:prompt => "Select a profile type"
%>
</div>
The drop down menu looks fine. But, how would I check which option is selected? I want to route to a different view based on this selection.
Thanks in advance!
The logic of routing to a different view should occur in your controller. When the user submits this form, check the value of the params, and perform your logic to route to a view:
class ExampleController
def routing
case params[:example][:type]
when 'foo'
redirect_to foo_path
when 'bar'
redirect_to bar_path
end
end
You can create a custom action name, since this routing isn't one of the CRUD operations. You will need to place this route into the config/routes.rb file if it is a custom name.
Optionally, you can bind to the select's onChange event, as mentioned by others to auto-submit the form when the user changes the value. This would still send the data to the controller and perform a redirect. The advantage to this approach is that you can keep your route information out of Javascript, and in the Rail's controller.
More on Rails routing can be found here: http://guides.rubyonrails.org/routing.html
More on Javascript binding to onChange can be found here: http://www.w3schools.com/jsref/event_onchange.asp
You should be able to use jQuery or any other popular Javascript framework to achieve this -- either attach an onChange listener or set the value somewhere and check it. Events, yay, etc.

How can I create this dynamic form?

Imagine a dropdown with 3 options:A,B,C and a div with the id of myform.
When the user selects an option from the list, the div's content should be replaced by the form corresponding to the option. The thing is, the forms have nothing in common.
I was thinking of tackling this in the following way:
create a new controller FormCreator
create a new action build_form , which will take a type as a parameter (A/B/C)
create A.html.erb, B.html.erb and C.html.erb
depending on the type, I will render either A/B/C, with layout rendering disabled
use ajax to replace the content of the div with what the controller produced
Is there a better way of doing this?
Here's guideline how I would do it: When some option is selected, for example A, with AJAX GET AController#new as JSON and return form rendered by erb. Than $('#myForm').html(withResponse). Main idea is that on select.change event you hit correct resource controller new action and replace div content with it's response.
Not complete answer but I hope it will give you an idea
Why not just hide the forms and reveal/hide them upon select list selection? It doesn't matter which controller or action you render the forms/select list from but they should probably post to their own controller and render only the previously posted form on validation failure.
Use a javascript select to call your AJAX controller with :onchange => remote_function(...)
In your controller =>
def FormCreator
if params[:form] == 1
render :update do |page|
page.replace_html 'form_div', :partial => 'form_1'
#make a file with just the form called _form_1.erb, this is called a partial
#because the file name starts with '_'
#form_div is the id of the div that holds all 3 forms.
end
end
#repeat for all forms
end

Should my edit and new actions re-use the same view? (editing a post)

I have this setup in my routes:
namespace :admin do
resources :posts
end
so in my admin/posts_controller.rb I have my new, create and edit actions.
I want to re-use my new and edit view page somehow, b/c the page has allot of custom javascript etc. for the form and I don't want to repeat myself.
How can I do this?
i.e. for the edit page, I have to pre-populate the form fields and for the new page it is to be empty.
For a new page, it should post to the 'create' action, and for the edit I am thinking it should post to a different 'update' action (which is a PUT request as per my rake routes)?
Rails is pretty clever, a form like
<% form_for post do |f| %>
<% end %>
will post to the create action if post.new_record? == true and to the update action otherwise.
So, you can put the form in a partial, and render it inside your new/edit views, which will probably have different headings and copy.
Alternatively you can just have a single view and perform your own logic based on post.new_record? - but I'd advise against this because you'll end up with an unnecessarily complex view.

Resources