Rails - how can I create an ajax link for row highlighting - ruby-on-rails

I have a great example of instant row hilighting that I want to do:
http://www.mrc-productivity.com/techblog/?p=684
How can I create a Turn on row highlights link with rails.
I have tried many combination of link_to and button_to with :remote => true but I can't get the syntax right and everything seems to end up with a regular link.
At the end of the day I am trying to turn on and off row table highlighting as in:
html:
Turn on row highlights
jquery:
$(document).ready(function() {
$("a.on").click(function(){
$("tr:nth-child(odd)").addClass("two");
$("tr:nth-child(even)").addClass("one");
event.preventDefault();
});
$("a.off").click(function(){
$("tr:nth-child(odd)").removeClass("two");
$("tr:nth-child(even)").removeClass("one");
});
});

You can easily create a link like that with:
link_to('Turn on row highlights', '#', :class => 'on')

In this case, you don't need to use the Rails helpers at all. You can simply use that link tag directly in an erb file:
Turn on row highlights
or for HAML:
%a.on{href: '#'} Turn on row highlights
The Rails view helper are only useful when you're linking to a Rails resource. The remote: true option is used when you want to unobtrusively access a resource with AJAX. Neither apply in your case.

Related

Rails - Change boolean value on link click

In my app I have user notifications where the user gets notified for certain actions. These notifications are being shown in a dropdown from the navbar (like Facebook or S.O.). All of the notifications have a boolean attribute called :read and are default set to false. I'm using bootstrap with the dropdowns (in case that helps).
I want to create a method where when the user clicks to open the dropdown, all of their unread notifications become read.
Here is what I have so far for the method.
def read_notifications
PublicActivity::Activity.where(recipient_id: current_user).where(read: false).update_all(:read => true)
end
This updates all of the current user's notifications to :read => true when the method is called. In the view here is what I had so far for the dropdown link.
<%= link_to read_notifications_path, :class => "dropdown-toggle notifications_icon", :'data-toggle' => "dropdown", :controller => "application", :action => "read_notifications", :method => :post do %><% end %>
and the routes.rb I had this.
match "/read" => "application#read_notifications", :as => "read_notifications", via: 'post'
Now I know what I have is wrong, but even so when I click the link it does switch all of the user's notifications to read, it just acts also as a link (duh) and goes to a different page.
As you know, the link on a bootstrap dropdown is "#".
Does anyone know how I can set this up properly where when the user clicks the notification link in the navbar, ALL it does is open the dropdown and change the boolean value to true for all notifications.
I know this is possible, I just haven't been able to figure it out yet.
Thanks for taking a look at it.
EDIT
JS file
$(".notifications_icon").on("click", function(){
$.post("/read", function(data){
$('.notification_badge').text("");
});
});
View
<%= link_to "#", :class => "dropdown-toggle notifications_icon", :'data-toggle' => "dropdown" do %>
<span class="notification_badge"><%= find_unread_notifications_count(current_user) %></span>
<% end %>
This is Posting to the /read to read all of the notifications but it's not updating the count
You want a dash of unobtrusive JS. For example, SO has a class js-inbox-button that, when clicked, triggers updates on unread counts (both client and server). I won't dig into their JS source, but it's fairly simple to build.
You seem to already have a relevant class (notifications_icon), though you might want to use something else. When the link is clicked, use jquery $.post.
$(".notifications_icon").on("click", function(){
$.post("/read", function(data){
// remove unread count
$('.notification_badge').text('');
});
});
Now this is a very basic implementation. Couple of suggestions:
Only make requests when necessary (check for unread count on page first)
Use a data attribute on the link to pass /read path. That way you can still use your path helpers instead of hardcoding a path.
Store the above JS in a separate file (unobtrusive)
AJAX.
By adding remote: true you're starting with AJAX. Now the call goes to your path, and nothing happens! yay!
You want something to happen, though. So in your controller (I wouldn't do it in the application_controller, if I were you... activities_controller.rb maybe?):
controllers/activities_controller.rb
def read_notifications
PublicActivity::Activity.where(recipient_id: current_user).where(read: false).update_all(:read => true)
respond_to do |format|
format.js
end
end
You're on your way to Asynchronous loading! Now you need a js file to match it. So, since you've already moved this action to the activites, in your view, you'll have a new js.erb file to create (notice that it's in the same folder in the views as the controller name, and the file is named after the action):
views/activities/read_notifications.js.erb
$('#your_menu_div').html("<%= j render partial: 'activities/notifications' %>");
Now you create a partial (views/activities/_notifications.html.erb) that gets rendered into your pulldown menu.
Clear as mud?

Kaminari with AJAX, unable to paginate

I've followed the AJAX Kaminari example here: https://github.com/amatsuda/kaminari_example/tree/ajax
I've successfully generated the partial and table. However, pressing the pages in the pagination does not update my table. In fact, upon pressing, the queries are the exact same data.
I found a similar problem, however the solution remains unanswered:
kaminari ajax pagination not updating the paginate
I can verify that I am using the #paginator element.
Some things I did do differently were instead of creating a separate js.erb file, I added
<script>
$('#paginator').html('<%= escape_javascript(paginate(#pending_requests, :remote => true).to_s) %>');
$('#requests').html('<%= escape_javascript render (#pending_requests) %>');
</script>
at the end of the of my html.erb file.
Also, in a view, I use an ajax request to select different data within the table. For example, I have a select_tag which upon selecting a user, the appropriate table is rendered using AJAX in the view. The table isn't a partial, it has its own view and method in the controller. At first I suspected that because of this, the table wasn't being updated. However, if I go to the table url, I am still unable to use pagination!
Edit: I am able to right-click the pagination links and open them to another tab. Clicking on them still doesn't do anything.
EDIT:
I wanted to add that I'm using Twitter Bootstrap. I noticed that if I set in my controller
format.html { render :layout => false }
Then I open one of the pagination links to another page, I can successfully paginate. I am using the Kaminari bootstrap theme however...
I didn't see a place to add a comment, so this is not a real answer.
Do only render the table with AJAX? Is the partial part of another page? Or is a stand alone view?
I had a similar problem (last post before your on the Kaminari tag page link where I had the option to render the table as a partial in a show view or as a separate page. that messed things up. I ended up, like you adding a script tag, but yours in not wrapped in a document ready function, so the page might not be fully loaded. Try.
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$('#paginator').html('<%= escape_javascript(paginate(#pending_requests, :remote => true).to_s) %>');
$('#requests').html('<%= escape_javascript render (#pending_requests) %>');
})
</script>

:remote => true with url_for, How does one do this?

I am trying to make an entire div tag clickable. The code I am trying to use is below, and when I add the
:remote => true
bit it throws Too many args error, 2 for 1.
Code:
<div id="foo" onclick="window.location = '<%= url_for foo_controller_path(:someparam => #left), :remote => true %>'"></div>
url_for doesn't accept the :remote => true argument, it's usually the link_to method that you would send it to.
Is there a reason you can't make your <div> a link instead? For all intents and purposes it is functioning as a link, so you should mark it up as such, we call that semantic mark-up.
If you really wanted to do this it would probably be best to use jquery (or prototype, if that's your cup of tea) to perform the action unobtrusively... it makes it easier to do the ajax request too. Are you trying to update something on your page after the link is clicked, or just do nothing?
Also the 'window.location' is telling the javascript on the page to redirect. You wouldn't use that if you wanted to make the request remotely.
Using jquery you could do it like this if you want to stick with a div
%(function(){
$('#foo').click(function(){
$.get(
url: $(this).data('request-path'),
success: function(data){
alert('success sir! controller responded with ' + data);
}
);
});
});
And use this in your view:
<div id='foo' data-request-path='<%= url_for foo_controller_path(:someparam => #left) %>'></div>
But if you changed it to a link tag you could do this instead...
= link_to("", url_for(foo_controller_path(:someparam => #left)), :remote => true, :id => 'foo')
And it ought to just work. Then you can style this link the way that you were trying to style your div tag.
This is more semantic and less code for you to worry about. If you need to update something in the dom afterwards you can add this jquery (if you're using jquery, and rails3):
$('#foo').bind('ajax:success', function(data){
alert('successful request! data was: ' + data);
});
I didn't necessarily test all of this but it should be a good starting point... I'm not a big fan of putting onclick handlers into tags. It tends to work nicer when you bind events using jquery.
If you want to be able to do what i've described but you're in rails 2, you can get the rails3 jquery script from here: https://github.com/rails/jquery-ujs
Note that you'll also need that script if you're using rails 3 and want jquery instead of prototype (like me!). Rails 3.1 will come bundled with jquery instead of prototype I hear, by default.
And change the :remote => true in that url_for to "data-remote" => true (for rails 2, with rails 3 you can use the symbol syntax and it makes the 'data-remote' attribute for you.
Let me know if something didn't quite work or you need clarification. Or even if you hate my ideas alltogether :p

Ruby on Rails: form and radio button question

I have a form around a list of items. I would like to check a radio button on the list and then, after clicking 'Submit', go to the 'Edit' page of the selected item.
The problem is that if I am writing something like
<%= form_tag edit_item_path %>
but Rails complains that I didn't provided a proper id, which in turn is being set on my radio buttons as the following:
<%= radio_button 'item', 'id', item.id %>
So - how would I send a form with a selected id to a given action?
Doing it the way you describe would not work, since edit_item_path by default RESTful path definitions is a GET request. You are trying to make it a POST request. If you would like to stick to the RESTful way of doing things I would recommend simply looping through your items and provide links to edit, since you are planning to edit them one at a time anyways. Otherwise, you would have to define a new route if you would prefer doing things within the form with radio buttons. If you are, than you would add something like this to your config/routes.rb: (assuming you are using rails 2.3.x)
map.resources :items, :member =>{:edit_radio_form => :post}
Than your form would look like this:
<%= form_tag edit_radio_form_item_path do |form| %>
And it should work, but it not the right way of doing things for several reasons, the most anoying one of which is that you won't get a full URL on your edit page because you got there with a POST request, so if you refresh the page, your item id param will be gone and will produce an error.

Attaching onClick event to Rails's link_to_function

How do I attach an onclick event to a link_to_function such that clicking on the event refreshes an element on the page (using partials)?
When the user clicks the generated link, I'd like to refresh the partial containing the code so that i gets updated.
def add_step_link(form_builder)
logger.info 'ADD_STEP_LINK'
link_to_function 'add a step' do |page|
form_builder.fields_for :steps, Step.new, :child_index => 'NEW_RECORD' do |f|
logger.info 'inserted js'
html = render(:partial => 'step', :locals => { :step_form => f, :i=>#i+=1})
page << "$('steps').insert({ bottom: '#{escape_javascript(html)}'.replace(/NEW_RECORD/g, new Date().getTime()) });"
end
end
end
I have a partial in a larger form that contains just:
<%= add_step_link(technique_form) %>
I am attempting keeping track of the number of steps in a technique. In the form I am creating, users can add new steps to a set of instructions. Right now, I have default fields for steps 1-7. Adding one step, gets you step 8. The problem is that subsequent steps are numbered '8' also.
I am extending the "Multiple child models in a dynamic form" tutorial in http://railsforum.com/viewtopic.php?id=28447 for my own purposes.
Ok, I'm a little confused about what you are doing, but I'm going to try and make some suggestions.
Rather than use link_to_function, use link_to_remote. Link to function calls javascript, but what you actually want to do is call back to a controller that then runs some rjs to either replace the full partial or, more likely, append the new partial (containing the step) to the end of your current steps.
This is similar to all those examples you will have seen where people append a comment to the end of their blog comments (expect using link_to_remote rather than remote_form_for) see 3/4 of the way through http://media.rubyonrails.org/video/rails_blog_2.mov
You can see the docs for link_to_remote here: http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html
I suggest using link_to_remote as RichH suggests. The trick for you it seems is keeping track of #i. I'd either put it as a URL parameter in link_to_remote, or in the session object. I'd suggest the session—it seems easier.

Resources