Make a Select Box that Calls a Method - ruby-on-rails

I have a rails app with working reports that have tags. In the Report/Index.html.erb I want the user to be able to sort the reports by selecting a tag. They may only select one tag at a time so I feel that a select box would work best. I currently have this:
<%= select("preferences", :tag_with,
["Politics", "Technology", "Entertainment", "Sports", "Science", "Crime",
"Business", "Social", "Nature", "Other"], :prompt => "Filter Feed by:" )%>
I have a working preferences controller with a method call tag_with that updates the current tag. This code, however, only generates the select box. I want it to be that when the user selects one of the tags, it calls the tag_with method from the preferences controller.
I generated a series of link_to lines that complete the task, however I would really like a select box.
<%= link_to "Politics", :action => "tag_with", :tag => "Politics", :controller =>"preferences" %>
<%= link_to "Entertainment", :action => "tag_with", :tag => "Entertainment", :controller =>"preferences" %>
<%= link_to "Science", :action => "tag_with", :tag => "Science", :controller =>"preferences" %>
<%= link_to "Technology", :action => "tag_with", :tag => "Technology", :controller =>"preferences" %>
And so on for each tag. This works fine but is bulky and undesirable. Is there a way to do the same thing through a select box?

In your reports.js.coffee file, or whatever other js file you want.
jQuery ->
$('select#preferences').change ->
$.get 'preferences/tag_with',{ term: $('option:selected', this). val() }
Or, if you want to use regular javascript:
$(function(){
$('select#preferences').change( function() {
$.get('preferences/tag_with',{term: $('option:selected',this).val()});
});
});
A link is a GET request. The jQuery .change() method fires whenever someone makes a change. The $.get method sends a GET request to a URL and can pass data (the second argument). This data becomes your params hash, so in the example above you would get:
params[:term] #=> the value attribute of whatever option was selected by the user
See the jQuery docs on .change() and $.get() for more help.
Update
For this to refresh the page, the easiest thing would be to extract the table that you want changed into a partial, let's assume it's called _report.html.erb. The partial should look something like this:
<div id="report">
<%= render #report %>
</div>
*Note: render #report is just short for render :partial => 'report'. See http://guides.rubyonrails.org/layouts_and_rendering.html*
In your preferences controller, tag_with option you should be sure to set the #report object (or whatever else is delivering the data to your partial).
Then you should make a file called views/preferences/tag_with.js.erb and put something like this in it:
$('div#report').html('<%= escape_javascript( render #report ) %>');
This will update the report container with the new content.

Related

Render object attributes on the same site with click

There's this button / link in my web app. It's a button for a pizza - margherita with price, ingredients, and category, all already loaded to the db. Clicking this button loads the item's id to params, which is then used to find the object.
I want the click to launch the following chain of events:
Load the id
Find the object by id
Instantly render the object and its attributes in adjacent div on the same site.
Is this possible without JavaScript, just Ruby on Rails?
I am stuck at point 3. I have an idea, but incomplete. Please, give me a hint.
PS. My idea is to render views for index and show in separate divs next to one another.
#NickM, I added your code and it's throwing ActionController::UnknownFormat error, pointing at respond_to do |format| in show_pizza method.
Here's my pizzas/index.html.haml:
%h1= t :all_pizzas
- #pizzas.each do |pizza|
= render pizza
.orders
%h1 Orders
And pizzas/_pizza.html.haml:
%tr
= link_to pizza.name, show_a_pizza_path(pizza.id), :method => :post
%br/
I am getting this error upon clicking the link in _pizza.html.erb. My show_pizza.js is now:
pizza_div = $("#orders");
pizza_div.html( "<%= j render( :partial => 'pizzas/pizza', :locals => { :pizza => #pizza } ) %>" );
What am I missing? Sorry, I don't know js.
The short answer is no. When the link is clicked you will need to either render another page or handle the data returned by the controller with Javascript. The best option would be to set up an action that responds with JSON and parse what you get back on the front end.
Even after your P.S. you will have to handle the response from the server with Javascript, unless you are okay with rendering a new page. You need to post some code, preferably routes and controller action. This would also work:
<%= link_to("Show Pizza", show_a_pizza_path(#pizza.id), :method => :post, :data => {:remote => true}) %>
routes.rb
post 'show_pizza/:id' => "pizzas#show_pizza", :as => :show_a_pizza
pizzas_controller.rb
def show_pizza
#pizza = Pizza.find(params[:id])
respond_to do |format|
format.js
end
end
views/pizzas/show_pizza.js
pizza_div = $("#the_name_of_your_div");
pizza_div.html( "<%= j render( :partial => 'pizzas/pizza', :locals => { :pizza => #pizza } ) %>" );
and then put the pizza markup in /views/pizzas/_pizza.html.erb

Add form in sidebar

In my ActiveAdmin app, I need to have a form in the sidebar (only for the show method) that will show a single (for the moment) datepicker. Once user click on the datepicker, the whole page should reload taking into account the date selected (within the show controller).
Any idea on how to add this simple form in a sidebar ?
EDIT
I tried the following but I'm not sure how the form can target a dedicated controller other than the current model.
sidebar :history, :only => :show do
form do |f|
f.input :start_date, :as => :datepicker
end
end
How can a form in a sidebar can target another controller than the one of the current model ?
I presume you have a show controller and don't mean the show action.
make the view into a partial called "whatever" (I call it this)
So, your whatever.erb.html looks like this
<%= render "whatever" %>
If you use Jquery Ui datepicker, you can add a onSelect function
$(".date").datepicker({
dateFormat: "yy-mm-dd",
onSelect: function() {
$('#range_form').submit();
}
}).attr( 'readOnly' , 'true' )
If you want a range add a form tag in your view with two date fields, else you just add one
<%= form_tag('/range', :id => "range_form", :remote => true) do -%>
<%= text_field_tag 'from', Date.now.strftime("%Y-%m-%d"),:class => "date"%>
<%= text_field_tag 'to', Date.now.strftime("%Y-%m-%d"), :class => "date"%>
<% end %>
For this you'll have to add a route in your routes.rb
match "/range/" => "show#todo_range", :as => :range
In your show controller
def range
time_range = ((Date.parse(params[:from]).midnight..Date.parse(params[:to]).midnight)
#whatever = Whatever.where(:date => time_range)
end
Then add a js view to handle the callback
$(".maindiv").empty().append(<%=j(render #whatever)%>)
I have not tested this exact code, so watch out for typos.
Good luck and comment if I need to edit

Rails - Render partial inside Twitter Bootstrap popover

I want to use a Twitter Bootstrap popover to display a user avatar and email address, with the possibility of adding in more details at a later date.
I am having an issue getting the partial to render inside the content field of the link. The view code is below (in HAML).
%span.comment-username
=link_to comment.user_name, "#", "title" => comment.user_name,
"data-content" => "=render 'users/name_popover'",
class: "comment-user-name"
Currently, this will only produce the content code as a string.
Is there a way to do this so the partial will be inserted instead of the code as a string?
You want rails to actually evaluate the content of the string and not just show the string. The easiest way to do that would be:
%span.comment-username
=link_to comment.user_name, "#", "title" => comment.user_name,
"data-content" => "#{render 'users/name_popover'}",
class: "comment-user-name"
That should pass the render statement to rails and render your partial as expected.
Thanks for the answer jrc - it helped me find a solution.
My solution might be useful for other non HAML people like me:
`<%= link_to('Service History' , '#', :class => "popover-history", :rel => "popover", :"data-placement" => "bottom", :title => "Service History", :"data-content" => "#{render 'services/service_history'}") %>`
with
`$(function () {
$('.popover-history').popover({ html : true });
});`

Add a :filter param to the end of a url

I am building an application that requires a search to go deeper than the initial level. I am using nested scopes to accomplish this and params in the URL
For example, when a user searches for "handbag" it creates a query like the following.
http://localhost:3000/junks?search=handbag&condition=&category=&main_submit=Go!
I want to add a :filter param to the end of this url and reload the page with the new url.
http://localhost:3000/junks?search=handbag&condition=&category=&main_submit=Go!&filter=lowest_price
As shown above the &filter=lowest_price is added to the query. I have already written controller code to handle this and I know it works as long as the query is like the 2nd link above.
my views code
<div class = "filter_options">
<p>
<strong>Filter by:</strong>
<%= link_to_unless_current "Recent", :filter => 'recent' %> |
<%= link_to_unless_current "Lowest Price", :filter => 'lowest_price' %> |
<%= link_to_unless_current "Highest Price", :filter => 'highest_price' %>
</p>
</div>
This is how I have it currently, which works if my URL does not have a search string attached to it. Unfortunately, this will go to a http://localhost:3000/junks?filter=lowest_price even if there is a search string. I would like to know how to create my links so that they add onto the search string shown in the 2nd code example.
Additionally, if a search string with a filter is already present, it would only change that filter and resubmit the search string with the new filter. I hope I am being clear.
You mean, something like:
link_to "Recent", url_for(params.merge :filter => 'recent')

Using sortable_element in Rails on a list generated by a find()

I'm trying to use the scriptaculous helper method sortable_element to implement a drag-and-drop sortable list in my Rails application. While the code for the view looks pretty simple, I'm really not quite sure what to write in the controller to update the "position" column.
Here's what I've got in my view, "_show_related_pgs.erb":
<ul id = "interest_<%=#related_interest.id.to_s%>_siblings_list">
<%= render :partial => "/interests/peer_group_map", :collection => #maps, :as => :related_pg %>
</ul>
<%= sortable_element("interest_"+#related_interest.id.to_s+"_siblings_list", :url => {:action => :resort_related_pgs}, :handle => "drag" ) %>
<br/>
And here's the relevant line from the partial, "interests/peer_group_map.erb"
<li class = "interest_<%=#related_interest.id.to_s%>_siblings_list"
id = "interest_<%=related_pg.interest_id.to_s%>_siblings_list_<%=related_pg.id.to_s%>">
The Scriptaculous UI magic works fine with these, but I am unsure as to how to change the "position" column in the db to reflect this. Should I be passing the collection #maps back to the controller and tell it to iterate through that and increment/decrement the attribute "position" in each? If so, how can I tell which item was moved up, and which down? I couldn't find anything specific using Chrome dev-tools in the generated html.
After each reordering, I also need to re-render the collection #maps since the position is being printed out next to the name of each interest (I'm using it as the "handle" specified in my call to sortable_element() above) - though this should be trivial.
Any thoughts?
Thanks,
-e
I typically create a sort action in my controller that looks like this:
def sort
order = params[:my_ordered_set]
MyModel.order(order)
render :nothing => true
end
Don't forget to add a route:
map.resources :my_model, :collection => { :sort => :put }
Now, on MyModel I add a class method that updates all of the sorted records with one query (this only works in mysql, I think..):
def self.order(ids)
update_all(
['ordinal = FIND_IN_SET(id, ?)', ids.join(',')],
{ :id => ids }
)
end
The single query method comes from Henrik Nyh.

Resources