Rails 4 - link back to form without reloading - ruby-on-rails

Rails newbie here...please be kind...
I have an app that generates a unique paragraph of text (sampled from arrays and made unique based on criteria entered in _form.html.erb, rendered from the criteria/new page). On the criteria/show page, I have 2 links, one to generate a new unique paragraph using the same criteria, and one to return to the form and edit the criteria.
For the second link, I want to retain the criteria previously entered, as the user may want to only change one entry and not have to re-enter all of it. I've found plenty of information regarding ajax calls, respond_to, remote: true, but haven't found this exact answer or if I have, my brain is TIRED and failed to comprehend.
I've seen the suggestion in a similar question (How to come back to form without reset the values?) which talks about repopulating the data: "Just add the parameters (/myForm?param1=1&param2=2&param3=3) to the button url that leads back to the search form. Then populate the fields using the parameters. No need to use session variables." Sadly, I'm unclear about how to do implement this.
Would someone please be so kind as to walk me through either (preferably the simplest!) way of doing this?
Current links on show page (commented things are those that I tried unsuccessfully:
<%= link_to 'Generate Another!', criteria_path %> #regenerates text with current criteria
<%= link_to 'Enter New Information', new_criterium_path %> #this is the link I'm trying to change
<%#= link_to 'Enter New Information', new_criterium_path, :remote => true %>
<%#= link_to 'Enter New Information', { :controller => 'Criteria', :action => "new" } :remote => true %>
Controller new action (commented until I can make it work):
def new
#criterium = Criterium.new
#testing ajax stuff
# respond_to do |format|
# format.html
# format.json
# end
end
There's lots of talk about needing a new.js.erb file (or would that be show.js.erb?) and a div tag in my show(?) page but again, brain TIRED. I've attempted some of these things, then deleted from the code so as not to gak things up too much and be unable to remember what I did.
Please tell me what else you need from me in order to answer. Many thanks in advance!

Looks like you need to pass back params to your 'new' action, and then use them when instantiating Criterium:
<%= link_to 'Enter New Information', new_criterium_path(criteria: params[:criteria]) %>
def new
#criterium = Criterium.new(criteria: params[:criteria])
end

Related

Dealing with 2 models in 1 view

I have two models I'm trying to interact with in 1 view. The first model is Room and the second is Availability. 1 Room has many Availabilities.
On 1 Rooms page, I render out availabilities through a partial like this:
<% #room.availabilities.where("booking_id is NULL").order("start_time").each_with_index do |a|%>
Beside each availability I have a button to delete and update. The delete worked out fine since it was in my loop so I could do something like this.
<%= link_to("Delete", availability_path(a.id), method: :delete, remote: true) %>
But I'm having trouble with edit. I'm trying to do it through a modal which doesn't have access to the 'a' variable from the loop. So I'm not sure how to pass in the unique availability to the form
Button:
<!-- Edit button -->
<button type="button" class="btn btn-xs btn-primary" data-toggle="modal" data-target="#editAvailability"><i class='fa fa-pencil'></i></button>
<!-- Edit Availability Form -->
<%= simple_form_for #facility.availabilities.find(???), method: :put, remote: true do |f| %>
You should be able to do this with AJAX. I have an app that has a modal dropdown that lets me toggle pieces of equipment in or out of service with a button in the dropdown. You can use a route that points towards the Availabilities controller that renders a form in the modal. Mine is simple in that it just toggles, but I don't see why you can't use a form. I would move your query out of your view and make a helper that gives you the results of your query in a variable.
I can provide more detail but need to see a lot more of your current code. If you can post your controller and all of your view code for the modal. I don't know understand why you don't have access to the variable you need in the modal? If the modal has an AJAX call you should be able to populate it with any data available to your controllers.
edit
Take a look at this: https://coderwall.com/p/ej0mhg/open-a-rails-form-with-twitter-bootstrap-modals . Be sure and read the links at the end of this article, it has some StackOverflow examples that are spot on. I'm thinking link_to is the way to go:
<%= link_to 'Update, availabilities_edit_path(a.id), {:remote => true, 'data-controls-modal' => "modal-window", 'data-backdrop' => true, 'data-keyboard' => true} %>
This should open a modal and ask the availabilities#edit controller for a JS response. Make sure you have an edit action, I don't see one in your controller:
availabilities.rb
def edit
#availability = Availability.find_by(id: params[:id])
respond_to do |format|
format.html
format.js
end
So the JS call will cause it to look in the /views/availabilities/ folder for a file called edit.js.erb with content like:
$('#editAvailability').html('<%= escape_javascript(render :partial => 'editForm') %>');
In your edit form you you now have the #availability instance variable to use in your form:
<%= simple_form_for #availability, method: :put, remote: true do |f| %>
...
So your modal gets built using an AJAX lookup that returns a form built using the needed instance variable. I'm putting this together from stuff I've written and other stuff I've read, so there will probably be some errors and tweaking to get your code working. Let me know how far this gets you.
You can store all the information necessary in your update button within your loop like this:
<%= link_to("Update", method: :put, remote: true, data: { attr1: a.attr1, attr2: a.attr2 }) %>
Then every button knows what entity they are operating for.

setting a dynamic link_to rails

I'm pretty new to rails and I'd like to set my links for a certain page dynamically. I have a table called "Unfinished" and it has a column called "link" (corrected from "links") I'd like to be able to call the "link" record in the view to set my link_to link path.
I am trying to do this...
<%= link_to #unfinished.link(:p => #post.id) do %> FINISH <% end %>
...but that's not working.
my controller says:
def show
#post = Post.find(params[:id])
#unfinished = Unfinished.where('progress = ?', #post.progress).last
end
and the controller logic works fine...until I try to put the #unfinished.link into link_to
Edit:
Error Message:
wrong number of arguments (1 for 0)
Model
class Unfinished < ActiveRecord::Base
end
The type of links are :
step1_path
step2_path
step3_path
I am making a multipage form that you can save partway through. Based on a value in the #post.progress column (like 1, 2, 3) the correct path to complete the post will be provided (step1_path, step2_path etc...)
try this.
<%= link_to eval(#unfinished.link.to_s) do %> FINISH <% end %>
since the link you want is actually a named route, so you will need to eval it.
but with this you wouldn't be able to be able to pass in the post id, which you will need.
If the route is the same for all records (save for what part you are on based on the progress attribute) do you even need to store it in the database? You could just make the link method return the path (that you would still need to eval).
something like
def link (post)
"step#{self.progress}_path(post.id)"
end
and then eval the link on the way back. but Not sure if that will work, just thinking out loud...
There are gems that do multi-stage forms perhaps looking into them might help?

How do I create a button that increments an attribute of a model and can be pressed once per browser?

An apartment_listing has many reviews, and a review belongs to an apartment_listing.
In the file views/apartment_listings/show.html.erb, I show a list of reviews for that particular apartment_listing. These reviews are generated with the partial view apartment_listings/_review.html.erb like so:
<%= render :partial => "review", :collection => #apartment_listing.reviews %>
In _review, I want to have a button that, when pressed:
Increments that review's helpful_count attribute.
Makes it so that it cannot be pressed again while in the same browser - probably using cookies.
I feel like the former shouldn't be too hard to figure out, but it's got me beat. I'm really not sure where to start with the second goal.
EDIT: I managed to update the review's helpful_count attribute with this code in apartment_listings/_review.html.erb:
<%= form_for review, :method => :put, :remote => true do |f| %>
<%= f.hidden_field :helpful_count, value: (review.helpful_count + 1) % >
<%= f.submit 'Helpful?' %>
<% end %>
However, I'm not sure if this is the best way to do it, and I'd like to be able to disable the button after it is clicked.
Your code for updating helpful_count has the potential for problems. Imagine two users have loaded an apartment on their web page. One of them marks it helpful, and the next one does as well. Since when they initially loaded the page, helpful_count was the same, after both of them click helpful, the count will only be incremented by one: it would be updated twice to the same value.
Really, you want to create a new action, probably under the reviews resource for an apartment. That action could use ActiveRecord's increment method to update the helpful_count (technically there's still a race condition in increment!, you'd encounter it much less often) http://apidock.com/rails/ActiveRecord/Persistence/increment%21
Cookies seem like a reasonable solution for the latter problem. Simply bind to submit on the form with jQuery, and create the cookie in the handler.
What does the code look like in your reviews controller? More experienced RESTful coders might be able to speak more coherently on this, but the way I see it, incrementing the helpful_count attribute should be an action sent to the reviews controller. That way, you can create a link that performs the action asynchronously.
For example, inside _review.html.erb:
<% collection.each do |review| %>
<%= link_to "Mark as Helpful", "/apartment_listing/#{#apartment_listing.id}/reviews/#{#review.id}/incHelpful?nonce=#{SecureRandom.rand(16)}", :remote => true, :method => :put %>
# ... Do something cool with your review content ...
<% end %>
Inside your ReviewsController class:
def incHelpful
unless params[:nonce] == session[:nonce][params[:id]]
#review = Review.find(params[:id])
#review.helpful_count += 1
#review.update_attributes(:helpful_count)
session[:nonce][params[:id]] = params[:nonce]
end
render :nothing
# Optionally return some javascript or JSON back to the browser on success/error
end
Inside /config/routes.rb:
put "apartment_listing/:apart_id/reviews/:id/incHelpful" => "reviews#incHelpful"
The main idea here is that actions that edit a resource should use the PUT http method, and that change should be handled by that resource's controller. Rails' built-in AJAX functions are engaged by setting :remote => true inside the link_to helper. The second concept is that of a nonce, a random value that is only valid once. Once this value is set in the user's session, subsequent requests to incHelpful will do nothing.

AJAX/HTTP issue

I have this code for a link that evaluates whether or not there are tags to determine what the link text should say:
<%= link_to "#{(#video.topics.count == 0) ? 'Add descriptive topics so people can find your song!' : 'Edit Topics'}", '#', :id => 'edit_topics_link', :class => 'edit' %>
The problem is that my tagging system updates completely with AJAX, and this link text does not, so it is only updated to the correct link text after a page refresh. How can I make the text update with AJAX?
You can do this easily using jQuery!
Just fetch the update data from the server (using $.get or $.post) and then update the link using the text() function. Here's an example:
$.get('http://some.url',{},function(response) {
$('#edit_topics_link').text(response);
}
Pretty simple, isn't it?

Ruby on Rails 3, forms, ajax, nested, in-place editing, one-by-one. Best practice

Assume, that I have a complex nested form with many fields.
I want to edit its fields one-by-one in ajax way, so that every time I see form - it is in 'show' style (without fields to change information), but with possibility to switch any particular field or group of fields to 'edit' mode with it's own 'save' or 'update' button.
Solving this kind of problem, I ended up with two ways:
Extended use of Ryan Bates' complex-form-examples.
The disadvantage of this way is that every field (or group of fields) requires it's own code (i.e. javascript: 'insert_fields'), which renders corresponding 'edit' style form, so it results in page is overwhelmed by javascripts.
Second - is unified procedure of loading corresponding edit partials through ajax through special controller action (i.e. get_partial), which "render :do updates" given field's area by 'edit' form.
For given field or group of fields i have partials for 'edit' and for 'show'. When i need to switch that field to edit mode i send request (link_to ...,'/.../get_partial?partial=foo',:remote => true) with necessary params by ajax, and some controller#action renders that partial by javascript.
I think that second approach is better one, but I can't figure out how optimize it the best.
Are there any more elegant solutions to this problem?
What if you generated a normal 'edit' form (with all the nested fields, etc), and then had the javascript hide the fields and add the text of the field and an edit link next to it. So for example say your form looks like:
= form_for #foo do |f|
= f.text_field :name
and your javascript would do this to it (1):
= form_for #foo do |f|
= f.text_field :name, :class => "hide"
<the value of the field here>
= link_to "edit", "#"
then make your javascript add a click event to the edit links that, when clicked, does:
= form_for #foo do |f|
= f.text_field :name
= f.submit "Save"
then you'd need more javascript that makes the save button submit the form (ajax), and go back to (1) above

Resources