UJS - where do I put the js.erb? - ruby-on-rails

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

Related

How to prevent redirect after submitting data through a form

New to rails (programming as a whole), and I'm a little confused about routing.
I have a form in my view that takes someone's email, and then emails them once they hit submit. It works, but after I hit submit I'm being redirected to the view for the method I'm calling in order to mail the form. I don't want to be redirected, I want to stay on the same page. I have attempted using POST and PUT, but both redirect me. Am I using my controller incorrectly?
My controller has this method:
def mail
recipient_email = params[:email]
itinerary_body = params[:body]
x = ItineraryMailer.itinerary("#{recipient_email}", "#{itinerary_body}")
x.deliver
end
And here is the form from my view:
<%= form_tag({controller: "bookings", action: "mail"}, method: "post") do %>
<%= text_field_tag(:email) %>
<%= text_field_tag(:body) %>
<%= submit_tag("Email Me!") %>
My route:
match '/bookings', to: 'bookings#mail', via: 'post'
Thank you!
Since you don't have a redirect_to in your mail action Rails isn't redirecting you anywhere. Instead, it's just trying to render that action's view directly. However, I'm guessing that isn't the view you want rendered.
So, instead of trying to prevent a redirection (which isn't happening anyway) I would suggest that you take the opposite approach: use a redirection to get to the correct view. At the end of your mail action do this:
redirect_to action: :original_action_name
Where :original_action_name is the name of the action that gave you the view you want.
You could also use the render 'action' suggested in a comment, but that can cause problems in some cases where the current action may not have loaded or set up everything needed by the view you want to have rendered. Of course, you could just do that loading/setup in the current action but then you are doing the same thing in two places which isn't DRY.

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?

Calling custom controller method

I need to call a method on Button click from my view. Below is the code in my view:
<button type="submit" id="1"><%link_to "Done", {:controller => :summary, :action => :done_order}, {:method => :put }%></button>
On click of this button, I have to delete a row from table and update the view with updated contents. Below is the done_order method in my controller
def done_order
List.where(:tableno => #orders.first.tableno).delete_all
redirect_to :action => :index
end
When I click on button I need to delete all rows(for a particular table number) from 'lists' table and redirect to index, which will again fetch rows from lists table in #orders and pass it to view to populate.
In routes file I have defined as: put "summary/done_order"
Problem is its not performing anything on click. I have tried numerous suggested ways with button_to & link_to but everytime landing up with some error. If there's no error then nothing is being performed.
I believe there is some shortcoming in my understanding to implement this and I am missing something on trying alternate ways. Please advise. thanks.
You should setup a route for this:
# routes
resources summaries do
put :done_order, on: :member
end
This should allow to write something like this:
= link_to "Done", done_order_summaries_path(#summary), method: :put
I'm not sure what you've named your objects, but it doesn't seem you've followed convention. So that part is up to you, but that's the basic mechanism. Another note is that you've put a link inside a button tag. I'm not sure that's even valid. There's no need for you to do that. Just style your link to look like a button or use a button instead, or even a button with a form.

Rails: set a value using a link

I need help trying to create a link that submits an edit form.
Let's say I have a list of objects
Object - Color - Own?
Ball - Red - false - [button]
Hat - Blue - true - [button]
Shoe - Green - false - [button]
When I click on the [button] I want to set "Own?" to True.
Routes
resources :toys
Controller
def edit
#toy = Toy.find(params[:id])
end
def update
#toy = Toy.find(params[:id])
if #Toy.update_attributes(params[:toy])
flash[:notice] = "Toy Updated"
redirect_to #toy
else
render 'edit'
end
end
View
<h2>Toys</h2>
<% if #toys %>
<% #toys.each do |toy| %>
<%= toy.name %> - <%= link_to 'Set Own', edit_toy_path(:id=>toy.id, :owned=>'true')%>
<br/>
<% end %>
<% else %>
None
<% end %>
This is all about how you setup your controller actions. I'm not totally sure I understand how you want to use yours, but I have a similar case that I'll show you which I think you should be able to adapt to your situation.
In my case, I have a menu button that sets a value in the session to either keep a menu panel open or closed across any views a user looks at.
First, you need a controller action that is going to do the work you're interested in. I created a "SharedController" which handles application-wide things that don't belong to any particular view or other controller.
class SharedController < ApplicationController
# Used by AJAX links to set various settings in shared views
def edit
session[:admin_menu] = params[:admin_menu].to_sym if params[:admin_menu]
session[:advanced_search] = params[:advanced_search].to_sym if params[:advanced_search]
render :nothing => true
end
end
This controller action can set one of two values in the session, either: "admin_menu" (boolean) or "advanced_search" (boolean). Then certain views ask whether the session value for admin_menu or advanced_search is true, and if so they show the view.
You could use the same logic. Something like:
def edit
object= Object.find(params[:object_id])
object.own = params[:own]
object.save
end
To trigger this controller action with a link you need to have a route that accepts GET requests. edit is a logical choice.
resource :shared, :only => [:edit], :controller => 'shared'
Note: I think SharedController makes more sense than SharedsController, and edit_shared_path makes more sense than edit_shareds_path, so I had to specify :controller => 'shared' in my routes.rb.
Then you just need a link to a url with params. To add params onto a path you just add them to the path helper, like so:
edit_shared_path(:key => 'value')
You can retrieve these params in your controller via:
params[:key]
Make this a link like so:
link_to 'Set Own to True for This Object', edit_shared_path(:object_id=>object.id, :own=>'true')
NOTE: It's best to do this via AJAX, so be sure to set :remote=>true. If you don't use AJAX then you need to specify a redirect in your controller for what page should be loaded after this link is triggered.
In the case of my admin menu preference link, I need a link with two possible states. I generate these using a helper:
# Shows Admin Menu Button
def admin_toggle_button
if session[:admin_menu] == :on
link_to( 'Admin Tools', edit_shared_path(:admin_menu => :off), :remote=>true, :class => 'selected', :id => 'admin_toggle_button', :title => 'Hide Admin Menu' )
else
link_to( 'Admin Tools', edit_shared_path(:admin_menu => :on), :remote=>true, :id => 'admin_toggle_button', :title => 'Show Admin Menu' )
end
end
In a view I just call this using admin_toggle_button. You can do something similar if you like, but it's optional.
I hope that gets you on the right track, let me know if you have any questions.
EDIT: Based on your comment:
Links issue GET requests, which mean you're going to the EDIT action. See: http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
A further issue, you have resources :toys instead of resource :shared (which I used for this purpose). This means your link helper is already expecting a specific toy to edit, rather than handling a singular resource. See: http://guides.rubyonrails.org/routing.html#singular-resources
Your link would work if you changed it to be:
link_to 'Set Own', edit_toy_path(#toy, :owned=>'true'), :remote => true
... and set your edit action in your controller to the following:
def edit
#toy = Toy.find(params[:id])
#toy.owned = params[:owned]
if #toy.save!
head :ok
else
head :internal_server_error
end
end
See: http://guides.rubyonrails.org/layouts_and_rendering.html#using-head-to-build-header-only-responses
Now, be aware, you really should only do this with AJAX links, and you should normally not do it with your "real" controller. The reason is, now this is the only action that can be processed by EDIT, so your normal toys#edit view would no longer work.
You can get around this by create a new action and a new route, for instance:
resources :toys do
member do
get 'set_ownership'
end
end
Then simply take the same method above and call it set_ownership instead of edit. IE:
class ToysController < ApplicationController
...
def set_ownership
...
end
end
Hope that all makes sense.
The edit_toy_path method that your link_to method is calling is going to the edit action inside your controller. It's not going to the update method that I'm guessing you want.
Your link_to will need to change to something like:
<%= link_to 'Set Own', toy_path(:id=>toy.id, :owned=>'true'), :method => :put %>
But I question this particular approach. I don't think the variable will update correctly in the update action because it is not namespaced to the proper params[:toy] object that update_attributes is expecting. And in my quick and dirty tests I couldn't get it to namespace properly.
When I have a situation like the one that you are describing I usually setup another action, like toggle_ownership and I call that from my link_to with a :remote => true option. Then the controller toggles the attributes as desired.
Thus, my routes looks something like:
resources :toys do
member do
put :toggle_ownership
end
end
And my view looks like
<%= link_to 'Set Own', toggle_ownership_toy_path(toy.id), :method => :put %>
The controller sets the variable and renders back a toggle_ownership.js.erb file that updates the appropriate section of the page.
Hope that helps!

Ruby on Rails passing of parameters between views from link_to tag instead of submit_tags (having both on page)

I'm creating in my index page of my ruby on rails program, a list of the most commonly searched for terms in my database and hence each time a user selects a specific category this is written to another database.
What i would like it to create a hyperlink and pass a certain amount of parameters to a form like is usually done with a select_tag but instead with just a hyperlink, i would like to pass a set of hidden fields that i have on the page as well as what the user has selected.
To give you a better idea, basically i have the following structure in my program:
User inputs a search on (index.html.erb), user clicks on submit tag
action, user is taken to search.html.erb page and is displayed a set of refined categories + some fields, submit button,
user is taken to closest.html.erb (which uses parameters from the previous form by invoking the params[:searchSelected] and a few other params. )
I would also like to add this functionality:
Mimick this same operation, but instead of going in the search.html.erb, i would click on an already refined search category on the index.html.erb page (from a link_to , transmit as parameters which link_to the user has chosen + the hidden fields.
i Currently have this code
#stats.each do
|scr|%>
<%= link_to scr.category, :action => 'closest', :id => scr.category%>
I'm not sure if this is relevant, but i currently have the following routes in my routes.rb file
map.resources :stores, :collection => { :search => :get }
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
would anyone please assist me please? this is my first ruby on rails project and i would really like to find a way around this please
I am not sure if this is what you were thinking, but you can add additional parameters to the link_to tag. They are then available in your controller. So:
<%= link_to scr.category, :action => 'closest', :id => scr.category, :other_param => "test" %>
Will be available in your controller.
def closest
params[:other_param] == "test" #this will be true
end
i managed to resolve this by taking the params[:id] and then according to the value either set my own values (instead of the hidden ones in the index.erb which i had set manually anyway) and otherwise, continue as usual had i placed a regular search
View:
<%= link_to obj.ptc_devicename ,"/wiuconfig/hd?idval=#{obj.id.to_s}&val=#{#devicetype}",:value => obj.ptc_devicename,:id =>obj.id %><br/>
Controller:
#Heading= params[:val]
#id=params[:id]
value will be id is 2 and val is #devicetype

Resources