Rails Cancel Confirmation Reason - ruby-on-rails

I have an application, which contains calls. I want to be able to cancel the call and supply a reason for the call cancellation. So far I have my cancel action working in the controller, but I'm trying to figure out how to expand it so before it posts "cancel" to the call_status field it will also populate a cancel_reason field based on a drop down.
Here's what I have so far:
view code: cancel button
<%= link_to 'Cancel',
cancel_call_path(call),
confirm: 'Are you sure you want to cancel the call?',
:method => :post,
:class => 'btn btn-danger btn-mini' %>
controller code: cancel action
def cancel
#call = Call.find(params[:id])
attrs = {
call_status: 'cancel',
incharge_id: #call.units.first.incharge_id,
attendant_id: #call.units.first.attendant_id
}
attrs.merge!({ incharge2_id: #call.units.second.incharge_id, attendant2_id: #call.units.second.attendant_id }) if #call.units.count == 2
if #call.update_attributes(attrs)
#call.units.each do |unit|
CallMailer.cancel_call(unit.incharge, #call).deliver
CallMailer.cancel_call(unit.attendant, #call).deliver
end
redirect_to calls_url, :notice => "Call was successfully cancelled"
else
redirect_to calls_url, :error => "Whoops."
end
end
I want either the confirmation pop-up shown, with the reason for cancellation, or the cancel action tied to a different view with a small form, that includes a reason.

By default the confirm attribute in link_to uses a JavaScript window.confirm which is a simple yes/no that returns true/false.
If you want to do it all on the same page you You'll need to use JavaScript and Ajax to accomplish this. Something along the lines of adding an event handler on the Cancel link that will show a modal with a drop down. The result of this modal will then Ajax a POST request to the Rails app. There are a lot of jQuery Plugins that you can use to help you accomplish this in Rails.
The second option is the one you described which would be to use a separate action in your controller. In terms of UX I think the first option is a better route to go and isn't as scary as it sounds.

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?

Adding AJAX 'add to favorite' to this controller?

This is blowing my mind, and there is so much going on that I just need to ask here for help.
Right now, I have a listing of resources. Inside each resource, it allows someone to 'add it as a favorite' by clicking a link. I have it working with normal redirection, but as for integrating ajax so they can favorite without the page refreshing, I am completely lost...
Right now I have it as a "put" action it seems for CRUD 'update'
FavoritesController (update is the only action in this controller)
def update
#favorite = Favorite.find_or_initialize_by_resource_id_and_user_id(params[:id], current_user.id)
if #favorite.persisted?
#favorite.destroy
else
if #favorite.valid?
#favorite.save
end
end
redirect_to root_url
end
My view:
<%= link_to "", favorites_path(:id => resource.id), :class => "star#{star_post?(resource)}", :method => "put" %>
My routes:
resource :favorites, :only => [:update]
My JS:
$('.res-list .star').click(function(){
$.put('/favorites/?id=' + $(this).attr('data-id'));
return false;
});
There's a couple of ways to do this. You can use link_to_function through which you can pass a javascript method (you can even pass a custom one if you've defined it in the view or in application.js). In this method, you can set up your AJAX call to hit your update action.
View (using jQuery's put macro):
<%= link_to_function "AJAX Link", "$.put('/favorites/#{resource.id}');" %>
Another way to do this is to give your link an addition HTML selector. Again, you would need to write a bit of js to hit your update action. I tend to like this way because I like to use buttons and what not instead of <a href="#"> tags. (Though honestly I ended up just creating a button_to_function method that calls content_tag(:button) instead of content_tag(:a))
I would recommend starting off with this Railscast on basic JQuery and Ajax processing. It's a bit dated, but is pretty solid still and will give you the basics to get you started.
http://railscasts.com/episodes/136-jquery
It will give you an idea of how to attach the ajax call to the element on your page, handle request processing and craft a basic javascript view partial that will update the form for the user.
Good luck!

UJS - where do I put the js.erb?

My articles can appear on several sites, so as well as an article model with title, body etc and a site model with site_id, site_name etc, I have I have an article_site_permission model, with article_id, site_id and visible which can be either true or false.
On my article edit page, I've done a button_to:
<%= button_to 'Hide', article_site_permission_path(:id => #article_site_permission_id, :article_site_permission => {:visible => "false"}), :method => :put %>
This works - it changes the permission to false. And I can show the Show button which does the reverse.
Now I want to refresh the div that has the button in it by adding :remote => true to the button link. But where do I put my javascript?
Is it in the article_site_permission view - even though I'm looking at a view of the article itself?
Is it called update.js.erb?
Thanks for your help.
Update for clarity.
My button is on the articles/edit page. The button updates article_site_permissions. I want to go back to articles/edit and refresh the div that has the button in it.
I must edit the update controller for article_site_permissions, but where do I put the js to refresh the div?
In your controller, redirect to the action you want (index, show, etc.). Do a
respond_to do |format|
format.js
end
under that action in your controller. Then, in the corresponding view, have a file named
index.js.erb
Or replace index with whatever action, just be sure to give it the same name as the action that's calling it.
EDIT
I should also mention you are correct in adding the remote true to your button. It's hard to tell from your question what action you're trying to reach in which controller. If you're trying to access the show action of the ArticleSitePermission controller, you're doing well. However, it seems like you're not trying to route to show. Check out this link for more info on routing to different actions.
EDIT 2
This should do it.
<%= link_to 'Click me', {:controller => "article", :action => "update", :id => #article_site_permission_id },
:remote => true %>
Also, if all you want to do is redirect to the article, you don't need to do js. Just redirect to articles#show

Rails link_to :confirm for a specific page

I'm new to Ruby on Rails and would like to know that, if there is a way to strict link_to :confirm for a specific page. Because I'm putting this in every page, but I don't want it to show a confirm message in every page.
I'm adding the code here as well, but the formate it's incorrect in the textbox.
link_to "Home",'/', :confirm => 'Clicking OK Will Discard Any Unsaved Changes. Click Cancel To Return To The Home Page.'
You can make a helper like this to restrict by controller_name and action:
def link_home(link_options = {})
unless controller_name.eql?('some_controller') and action_name.eql?('some_action')
link_options.merge!{:confirm => 'Clicking OK Will Discard Any Unsaved Changes. Click Cancel To Return To The Home Page.'}
end
link_to "Home",'/', link_options
end

jQuery ajax call in Rails?

I want to execute a simple thing. When the user clicks the link jQuery needs to generate an Ajax request which sends the id of the link item to a method in the controller. Basically I want a nice looking modal dialog window when the user clicks the delete link. That window needs to contain various info about the deleted items.
E.g.
<%= link_to "Delete", item, :id => "delete" %>
I'm able to select this link with jquery and even to open a popup dialog when the user clicks it. Through application.js but what i really need is jQuery to call my method when the link is clicked and in my method I would answer via format.js. In the js file I place the code to show modal dialog with required parameters. All those actions asynchonous via ajax ofcourse.
I can't generate the ajax request to the method in the controller. Don't know already how to deal with the jQuery.ajax method, especially how to force jQuery to pass the url parameter to the rails method. I watched the railscast and studied the example with .post, but I don't need to submit any form.
Any advise is appreciated.
Thanks
Rails expects a post, with a hidden param.
$('#delete').click(function(e){
e.preventDefault();
$.post($(this).attr('href'), { _method: 'delete' });
});
Rails 3 has an unobtrusive way of doing this using a jQuery plugin:
http://github.com/rails/jquery-ujs
Once you have that loaded into your layout (with jQuery 1.4.1 or newer), you can do interactions like this pretty easily.
<%= link_to 'delete', item, :remote => true, :method => :delete,
:confirm => 'Are you sure?' %>
In Rails 3 all this does is add some HTML attributes to your link. These get caught by live handlers in the jQuery plugin. It's easy to use this behavior in a Rails 2 application, though:
<%= link_to 'delete', item, :'data-remote' => true, :'data-method' => :delete,
:'data-confirm' => 'Are you sure?' %>
Note that you need to have the jQuery plugin loaded in your view.
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
If you need the initial response to be a modal instead of an alert, you could make the first link a bit simpler:
<%= link_to 'delete', modal_confirm_item_url(item), :'data-remote' => true %>
You could link it to some pre-existing member action. Or since you may eventually want to use .js responses from those actions to serve other ajax requests, it may make sense to create a new action to handle this behavior.

Resources