Rails 3.1: Update Div with Link_to - ruby-on-rails

Here's what I have:
<%= link_to "Reload Div", {:controller => "my_controller", :action => "my_action"}, remote => true %>
I want to be able to click the link and have a div reload with different content generated by Ruby on Rails. How can I do this?
For simplicity... I simply want to be able to click the link and reload the div with a number one higher than the previous.

If you're using jQuery, this might be easier with UJS than by hacking something together yourself. Maybe something that does this:
$('a.reload').click(function() { $(this.parentNode).load(this.href); return false; });

If rails is incrementing the number, I'm not sure why you wouldn't just use link_to as you have specified in your question as you have everything set up correctly with your controller, action, and the remote attribute.
Here is your action:
def my_action
#counter = 1 #Insert whatever logic you need to increment the number.
end
Here is your view (my_action.js.erb):
$("#divtoreload").html("<%= #counter %>");

Related

Rails 4 - link back to form without reloading

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

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.

pass value of td element to rails controller

I'm trying to pass the value of a element to a rails controller!
Currently, I have something like this:
<td id="dbname"><%= link_to db, :action => :show %></td>
This represents a row in an html table, which contains a string value, e.g. "development".
When the user clicks on the "development" link, the <%= link_to ... %> grabs the value from the current clicked and passes that to a rails controller action, in this case the show action.
How can this be achieved!?
UPDATE - generating links:
<% #dbs.each do |db| %>
<tr>
<td id="dbname"><%= link_to db, :action => :show %> </td>
</tr>
UPDATE 2:
this is my index controller:
conn = Mongo::Connection.new
#dbs = conn.database_names #this returns an array of strings (which are the names of the databases)
Now I want to be able to click on of these databases and then to pass the clicked text to the rails controller show action. I'm not sure how I would generate a custom resources path for these links... but I was contemplating of doing it using Ajax or something javascript related. Maybe get the text of clicked link using jQuery and then send an Ajax request to the rails controller with the text as a parameter!
I think that it's a strange thing what you're trying to do, but a solution could be to use javascript to append the id to the href of each link as a query string.
If you could explain a little bit what you're trying to achieve maybe we could find a better solution.
Hope it helps!
Edit:
If you have a table of links I think that you should consider them as a resource and managing them the REST way.
Your controller should have an index and show action and you should declare the links as a resource in the routes file (maybe link it's a reserved word and you will have to use a different name, I'm not sure), the index action will fetch all the links and when you render them, you could specify the link for each one with something similar to "link_path(link.id)" (remember, you should have a show action defined) in the controller you will receive the link id so you could load it with a simple "find" and pass it to the view.
I recommend you to always look for the REST way to solve a problem in ROR.
Edit 2:
Ok let's see if this works for you:
I suppose that you have a model that represent those links that you're talkin about, for example:
class DataBaseLinks < ActiveRecord:Base
end
This model with be backed up by a table in your database, if you have generated it the rails way, you will also have an id column that identify each database link.
in your controller, let's say DataBaseLinksController, you'll have:
class DataBaseLinksController < ApplicationController
def index
#dabatase_links = DataBaseLink.all
end
def show
#database_link = DataBaseLink.find(params[:id])
end
end
(I've avoided all the validations and checks).
All you have to do in your index.html.erb is:
<% #database_links.each do |database_link| %>
<%= link_to database_link.name, database_link_path(database_link.id) %>
<% end %>
This will generate all the links with the correct path to the show action (maybe the route helper is a little bit different, but not so much).
Notice also that you'll have to add into your routes.rb the following line:
resources :database_links, :only => [:index, :show]
How do you see it?
Edit 3:
(I'll delete all my edited answers when we find a correct one)
Ok I'm going to suppose that you are not using something like mongoid so you don't have active record similar objects.
Have you tried this in your view:
<% dbs.each do |dbs_name| %>
<%= link_to dbs_name, :controller => "your_controller", :action => :show, :dbs_name => dbs_name %>
<% end %>

Rails select_tag onchange action WITHOUT Ajax?

In my index action of the hours controller I want to be able to switch between the diplayed hours.
I am using a calendar_for table and inside the calendar I display the tracked times (hours) of the different user of my rails app.
As I am using a quite complex calendar structure with some calculation inside, I don't know how to extract it to a partial, so I want the onchange event, which fires in the select_tag, to reload the index action with a different parameter.
I tried
<% form_for :hours, :url => { :action => "index" } do |f| %>
<%= select_tag :user_id, options_from_collection_for_select(User.find(:all), :id, :name),
{ :onchange => "this.form.submit();"} %>
<% end %>
but this brings me to the new / form view (like i want to add a new record)? also the url just shows /hours
Any help would be appreciated....
I basically want that after changing the select menu the url looks like /hours?user_id=<id from select_tag>
thanks
I do not quite understand why do you need a form? The simplest way from my opinion is update your application.js file with something like this (assuming you use jquery):
$("#selector_id").change ( function () {
window.location.replace('/hours?'+this.id);
});
Though probably there is some pretty rails helper for that.

Why does my RJS stop working when I set options in form_remote_for?

I am running into a strange problem.
I simply want to display a loading icon on the page when pressing a button.
If my call to form_remote_for contains Ajax options then the RJS script does not work.
This works ("loading" is hidden by the controller and RJS):
View:
<%=form_remote_for(:job, #job, {:url => {:action=>:create}}) do |f| %>
[...]
<div id="loading">Loading...</div>
controller:
def create
render :action => "create.js.rjs"
end
RJS:
page.hide 'loading'
This does not work (just adding :loading=> and loading is shown by the view but not hidden back by the controller as it was before):
<%=form_remote_for(:job, #job, {:url => {:action=>:create}}, {:loading=>"$('loading').show()"}) do |f| %>
[...]
<div id="loading" style="display:none;">Loading...</div>
So if my call to form_remote_for contains Ajax options then the RJS script does not work. Why?
Change your form to:
<% form_remote_for (:job, #job, :url => {:action => :create}, :loading =>"$('loading').show()") do |f| %>
# ...
<% end %>
Make sure create is:
# POST /jobs
# POST /jobs.xml
def create
render :action => "create.js.rjs"
end
And make sure your create.js.rjs is:
page.hide 'loading'
This scenario works for me. As you had it, it was returning the erb in the template because it was posting to "new" -- based on a quick scaffold implementation I did. Now I might still be missing something because as I said before the massive edit, I'm new, but this should get you going.
EDIT: Removed "is this your code?" post.
While not directly answering your question of "why" it isn't working, have you looked at using the :loaded parameter to hide the loading DIV rather than rely on the rjs file?
Assuming your using prototype you should use the Ajax.Responders to do the show/hide:
Ajax.Responders.register({
onCreate: function() {
Ajax.activeRequestCount++;
if($('loading') && Ajax.activeRequestCount>0) {
Effect.Appear('loading',{duration:0.4,queue:'end'});
};
},
onComplete: function() {
Ajax.activeRequestCount--;
if($('loading') && Ajax.activeRequestCount==0) {
Effect.Fade('loading',{duration:0.4,queue:'end'});
};
}
});
You can stick it in public/javascripts/application.js
Unobtrusive javascript - will work on any page with a hidden loading div and ajax events.

Resources