Need to pass parameters to ajax file - ruby-on-rails

I have a web page with a couple of buttons and each button loads information on the page through ajax. Each button calls the same action in controller. That action, called "load" then calls an ajax file which in turns loads different information on the page depending on which button was clicked.
My buttons in my html file look like this.
<%= button_to "Load Profile", { :controller => "surveys", :action => "load"} %>
<%= button_to "Load Personality", { :controller => "surveys", :action => "load"} %>
<%= button_to "Load Experience", { :controller => "surveys", :action => "load"} %>
The load action in the surveys_controller.rb file looks like
def load
respond_to do |f|
f.js { render 'shared/ajax/info.js.erb' }
end
end
The info.js.erb file looks like this
$('#email').empty().html("<%= j render(:partial => 'shared/survey/tech/profile') %>")
This has worked for me in other places but now the content i need to load differs. I need the "#email" and the "shared/survey/tech/profile" to be a parameter sent from the load action. Can anyone help me?

Since you have the same action and same js.erb file for each button therefore you need to send some data using your buttons in order to differentiate with of the buttons is clicked.
For that you need to follow these steps:
a. Create a post request for your custom method load
post 'surveys/load' => "surveys#load"
b. Send some data through your buttons which will differentiate them:
<%= button_to "Load Profile", { :controller => "surveys", :action => "load", :profile => "yes"} , :method=>:post, :remote => true %>
# this will make you access params[:profile]
c. Check inside your load method which button is being clicked using params:
def load
#profile = params[:profile]
#other params to store values of personality and experience
respond_to do |f|
f.js { render 'shared/ajax/info.js.erb' }
end
end
d. Inside your info.js.erb file you could check which one of the variable is equal to yes and then render accordingly
<% if #profile == "yes" %>
#render your partial
<% elsif #personality == "yes" %>
#render your partial
<% elseif #experience == "yes" %>
#render your partial
<% end %>
On a second thought i think it'll be better if we just separate out this logic inside controller and depending on the params value render different js files like:
def load
#profile = params[:profile]
#other params to store values of personality and experience
if #profile == "yes"
respond_to do |f|
f.js { render 'shared/ajax/profile_info.js.erb' }
end
elsif #personality == "yes"
respond_to do |f|
f.js { render 'shared/ajax/personality_info.js.erb' }
end
end
end

Try something like this and see if it works for you;
<%= link_to "Load Profile", { :controller => "surveys", :action => "load"}, remote: true %>
<%= link_to "Load Personality", { :controller => "surveys", :action => "load"}, remote: true %>
<%= link_to "Load Experience", { :controller => "surveys", :action => "load"}, remote: true %>
respond_to do |form
format.js { }
end
and then;
$('#email').empty().html("<%= j render(:partial => 'shared/survey/tech/profile') %>")

Related

Rails - Trouble Using Ajax on Like Action

I'm having a little trouble with using AJAX on something I've done before with no issues, but this site has a few different configurations which are causing trouble for me. The main problem I'm having, is when I click the Like link on a post, all of the like links on that page are changed to unlike, even though the one I clicked is the only one getting posted in the Database.
On my user's profile page (users/show.html.erb), I'm showing all of the posts (updates in this scenario) that the particular user has posted.
Here is my configuration thus far:
Users Controller, Show Action
def show
#updates = #user.updates.paginate(:page => params[:page], :per_page => 20)
end
Updates Controller, Like Action
def like
begin
#vote = current_user.vote_for(#update = Update.find(params[:id]))
if #vote.save
respond_with #update.user, :location => profile_path(#update.user)
end
rescue ActiveRecord::RecordInvalid
redirect_to #update
end
end
users/show.html.erb
<div class="like_button">
<%= render :partial => 'updates/like_button', :locals => {:update => update} %>
</div>
updates/_like_button.html.erb Partial
<% if current_user.voted_on?(update) %>
<%= link_to unlike_update_path(update), :method => :post, :remote => true do %>
<i class="ss-heart liked" title="Unlike Update"></i>
<% end %>
<% else %>
<%= link_to like_update_path(update), :method => :post, :remote => true do %>
<i class="ss-heart animate" title="Like Update"></i>
<% end %>
<% end %>
updates/like.js.coffee
$(".like_button").html("<%= escape_javascript render :partial => 'updates/like_button', :locals => {:update => #update} %>");
So just to refresh, the like button works and records the vote into the database, but it changes all of the like_buttons on the page to appear as if they have been liked instead of just the one post.
You need some way to distinguish your like buttons (by css class / id for example) and then you can alter them with jQuery concretely
$(".like_button").html("<%= escape_javas...
while currently $(".like_button") aims for all elements with that .like_button class (which are all).

Rails - modifying/duplicating default "show"

Is there anyway that I can modify the behavior of the default "show" ?
Currently when a user clicks on a button the main site
<%= link_to "ADD TO CART", product, {:class => "btn btn-primary", :target => '_blank', :method => "get"} %>
The user will be automatically redirected to a page with the appropriate information.
Now I'm trying to create a slightly different page (mobile friendly) and I've created a mobile_show page that works if I access it directly.
My question is how should I modify the link_to so that it points to /mobile/products/id instead of the current products/id ?
Update (Extra info):
In products_controller.rb`
# GET /mobile
# GET /mobile.json
def mobile
#products = Product.current
respond_to do |format|
format.html # mobile.html.erb
#format.json { render json: #products }
end
end`
# GET /mobile/products/1
# GET /mobile/products/1.json
def mobile_show
#product = Product.find(params[:id])
#product.update_attribute(:is_active, false)
respond_to do |format|
format.html # mobile_show.html.erb
#format.json { render json: #product }
end
end
In routes.rb
match '/mobile' => 'products#mobile'
match '/cashback' => 'products#cashback'
match '/mobile/products/:id' => 'products#mobile_show'
p/s: I'm very new to rails and web-development in general
You should actually create a namespace or controller specifically for mobile so it doesn't break REST
eg
app/controllers/mobile/products_controller.rb
or
app/controllers/mobile_products_controller.rb
But to use your method, you might want to add a name to your route so you can use it
match '/mobile' => 'products#mobile', :as => "mobile"
Then change your
<%= link_to "ADD TO CART", mobile_path, {:class => "btn btn-primary", :target => '_blank', :method => "get"} %>
based on your existing routes, you can change your route to
match '/mobile/products/:id' => 'products#mobile_show', as: :mobile_product
then in your view
<%= link_to "ADD TO CART", mobile_product_path(product), {:class => "btn btn-primary", :target => '_blank', :method => "get"} %>
UPDATE: is it good practice?
This actually depends on what you want to achieve. If you want to create a mobile version for your app, I suggest you look at a responsive ui. If that is not possible, the right way to handle this is to create a different set of controllers that will handle mobile requests.
These controllers should be placed under a different namespace.
namespace :mobile do
resources :products
end
This would expect you to have an app/controllers/mobile/products_controller.rb and handle mobile requests here.

Pass Rails variable from controller to JS

Problem description:
I have a view with set of links:
<% #feeds.each do |f| %>
<div class="feed">
<span class="feed_counts"> <%= f.display_counts %> </span>
<%= link_to "refresh", { :controller => 'Feeds', :action => "refresh_feed", :feed_id => f.id}, :remote => true, :class => 'refresh_feed_link' %>
</div>
<% end %>
Users click on the link and launch next controller method:
def refresh_feed
#feed = Feed.find(params[:feed_id])
#feed.parse
end
Now I want to change the content of the corresponding span-element to #feed.total_count value.
My attempts:
Well, as I know there is a two way's to do it without reloading whole the page:
Way 1:
I can include js in my layout:
<%= render :partial => 'shared/partial_js' %>
and use this code in the partial_js:
<script type="text/javascript">
$().ready(function() {
$('.refresh_feed_link').bind('click', function() {
$(this).closest('.feed').find('span.feed_counts').text('woo');
});
});
</script>
In this case I have '$(this)' and I can find the corresponding 'span' element. But I don't have any possibility to get my #feed varible value.
Way 2:
I can add
respond_to do | format |
format.js {render :layout => false}
end
to my controller and create refresh_feed.js.erb file. In this JS file I can use my variable as <% #feed.total_count %>, but I don't know which of my multiple links was clicked. In the other words the $(this) variable in this file will be (window) and I cannot find corresponding span-element.
Question:
Is there any way to get what I want ?
Thanks in advance.
There are lots of ways to do this. Using the wayds that you described, here's a simple solution for the "which link was clicked" problem: dom_id.
1) Make a partial: app/views/feeds/_feed.html.erb
<%= div_for feed do %>
<span class="feed_counts"> <%= feed.display_counts %> </span>
<%= link_to "refresh", { :controller => 'Feeds', :action => "refresh_feed", :feed_id => feed.id}, :remote => true, :class => 'refresh_feed_link' %>
<% end %>
2) In your view:
<%= render #feeds %>
3) In your refresh_feed.js.erb file:
$('<%= dom_id(#feed) %>').replaceWith('<%= escape_javascript( render #feed ) %>');
There's another way that I personally like better, but it will take a me a little while to write it up, so I'll leave this for you here while I write up the other way.
Second Way
Here's how I do it, using CoffeeScript and HAML because they're easier to type. You can just convert this to plain JS and ERB and it will work the same.
I would setup my routes like so:
resources :feeds do
get "refresh_feed", :on => :member
Assuming you've got a "feed" partial, app/views/feeds/_feed.html.haml:
= div_for feed, :class => 'feed_widget' do
%span.feed_counts= f.display_counts
= link_to "Refresh", refresh_feed_path(f), :class => 'refresh_link'
In any view:
= render #feeds
// or, more explicit:
= render :partial => 'feed/feeds', :collection => #feeds, :as => :feed
Now, in app/assets/javascripts/feeds.js.coffee
# Global Scope for CoffeesScript, ignore for JS
root = exports ? this
# Check page if there are feed widgets on it and initialize a handler for each one.
jQuery ->
if $('div.feed_widget').length
$('div.feed_widget').each ->
new FeedWidget $(this)
root.FeedWidget = (container) ->
#container = container
#refresh_link = #container.find('a.refresh_link')
#feed_counts = #container.find('span.feed_counts')
this.initialize()
root.FeedWidget.prototype =
initialize: ->
self = this
#feed_counts.click (event) ->
event.preventDefault()
$.ajax
type: 'GET'
url: self.refresh_link.attr 'href'
dataType: 'json'
error: (xhr, status, error) ->
console.log error
console.log xhr
success: (data, status, xhr) ->
self.feed_counts.text data.feed_counts
Then in your controller:
def refresh_feed
#feed = Feed.find(params[:id]) #assuming you have a resourceful route to this.
#feed.parse
respond_to do |format|
format.js { render :json => { feed_counts: #feed.counts }, :status => :ok } # use whatever method gets you the feed count here.
end
end
Now you are getting a JSON response that is just the feed count, and you have a single JS listener/handler widget that will automatically show up (and function) and place you render that partial. Cool huh?
Note, the above code is not tested since I don't have your app, so you'll have to refine it for your needs. But ask questions and I'll do my best to answer.
Good luck!

How do you recreate a remote link with the same .js update in Ruby on Rails?

Basically I want to make a link able to be refreshed dynamically from "Favorited" to "Removed", and at the same time give the user the option to go go back by reclicking the new button. The action does happen though, because when I refresh the page the updated button shows. Why does clicking the "Favorite this Classroom" link not work? The "Remove this Classroom" link seems to work. Thanks for your help
favorites_controller.rb:
def create
current_classroom.add_to_favorites(#classroom)
current_classroom.save
respond_to do |format|
format.js { }
format.html {redirect_to #classroom}
end
end
def destroy
current_classroom.remove_from_favorites(#classroom)
current_classroom.save
respond_to do |format|
format.js { }
format.html {redirect_to #classroom}
end
end
favorites/create.js.erb
$("#favorite_classroom").html("<%= escape_javascript(link_to 'Remove the Classroom', classroom_favorite_path(#classroom), :remote => true, :method => :delete) %>");
classrooms/_classroom_details.html.erb
<div id="favorite_classroom">
<% if loggedin_user.favorite_classroom?(#classroom) %>
<%= link_to 'Remove this Classroom', classroom_favorite_path(#classroom), :remote => true, :method => :delete %>
<% else %>
<%= link_to 'Favorite this Classroom', classroom_favorites_path(#classroom), :remote => true, :method => :post %>
<% end %>
routes:
classroom_favorites POST /classrooms/:classroom_id/favorites(.:format) {:action=>"create", :controller=>"favorites"}
classroom_favorite DELETE /classrooms/:classroom_id/favorites/:id(.:format) {:action=>"destroy", :controller=>"favorites"}
Error when I click on the "Favorite this Classroom" link:
ActionView::Template::Error (No route matches {:action=>"destroy", :controller=>"favorites"
Thanks!
You are using double-quotes twice in your js file. You can't do that. You need to rewrite it like this -
$("#favorite_classroom").html("<%= escape_javascript(link_to 'Remove the Classroom', classroom_favorite_path(#classroom), :remote => true, :method => :delete) %>");
Notice now that Remove the Classroom is enclosed in single quotes rather than double.
In addition, your route is incorrect because you have nested favorites within classrooms. When you write the link, you need to add the #favorite object that you are trying to delete:
= link_to 'Remove Favorite', classroom_favorite_path([#classroom, #favorite]), :remote => true, :method => :delete
Now the route you are trying to access is valid. That should get rid of the error.
I don't think you need the favorite controller, what you need is favorite/unfavorite action for classroom controller. Here's how it might look
classroom_controller.rb
respond_to :html, :js
def favorite
# ... find classroom by id
# do your stuff
#classroom.favorite = !#classroom.favorite
respond_with(#classroom)
end
views/classrooms/favorite.js.erb
<%# the message should be oposite to favorite %>
<% msg = #classroom.favorite ? "Remove this Classroom" : "Favorite this Classroom" %>
$("#favorite_classroom").html("<%= escape_javascript(link_to msg, [:favorite, #classroom], :remote => true) %>");
Here's the trick with path helper, [:favorite, #classroom] should be transleted to /classrooms/:id/favorite. If it won't work then try favorite_classrooms_path(#classroom)
And finally add to your routes.rb
resource :classrooms do
member { get :favorite }
end
Looks like you need to reference 'favorite_id' in your link to match your routes.
In your case, would probably be:
classroom_favorite_path([current_classroom, #classroom])

Execute contents of rjs after update

I would like to alert something after my form has been updated
This is my code for the update method:
def update
node_id = session[:node_id]
#node = Node.find(node_id)
respond_to do |format|
if #node.update_attributes(params[:node])
format.html {redirect_to add_loc_path(:node_id=>session[:node_id])} #redirects use to current page
format.js #allowing the update method to respond to JavaScript
end
end
end
This is the code of the form:
<% form_for #expression, :url => { :controller => "expressions", :action => "update" } do |f| %>
...
<%= link_to_remote "say Hello", :url => { :controller => "expressions", :action => "update" }, :method => :get %>
<%= f.submit 'Update' %>
<% end %>
update.js.rjs:
page.alert('Hello')
If i click on the remote link 'say Hello', the content of 'update.js.rjs' is alerted. However if i click on the 'Update button', nothing is alerted, in fact i get the error:
try {
alert("Hello");
}
catch (e) { alert('RJS error:\n\n' + e.toString()); alert('alert(\"Hello\");'); throw e }
I don't understand why update.js.rjs seems to work fine for 'link_to_remote' but gives an error when being called after clicking on the <%= f.submit 'Update' %> button
Is it possible to execute the contents of a rjs file after clicking on the Update button??
You should be using a remote_form_for instead of the normal form_for.

Resources