Add a :filter param to the end of a url - ruby-on-rails

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')

Related

Rails - Merge Multi-Select Params into comma-separated string

I have a select box that allows multiple values, to filter the results on the page. When I select multiple, the Parameters that are submitted look like this:
Parameters: {"categories"=>["books", "films"], "commit"=>"Submit", "id"=>"87"}
When I am returned to the page, the URL is:
http://localhost:3000/87/projects?categories%5B%5D=books&categories%5B%5D=films&commit=Submit
The URL I would like to return is:
http://localhost:3000/87/projects?categories=books,films
How can I return these params[:categories] as a comma-separated string in the URL? Also, is it possible to remove the "&commit=Submit" from the URL?
Here is my full form code:
<%= form_with url: project_path(#project), local: true, method: :get, skip_enforcing_utf8: true do |form| %>
<%= form.select(:categories, #categories.map {|category| [category.name,category.slug]}, options = { selected: params[:categories], include_blank: "Select Categories", include_hidden: false }, html_options = { multiple: true }) %>
<%= form.submit 'Submit' %>
There's a couple JS & Rails way to do what you want. I can think of a quick and easy one using rails only: Redirecting the URL you are getting to another route with the data parsed as you want it. Like this -->
Assuming this is your route to project_path : get 'project', to: 'project#reroute', as: :project
You can go to your reroute method in the project controller and parse the data you got.
project_controller.rb
class ProjectController < ApplicationController
def reroute
redirect_to your_path(categories: params[:categories].join(','))
end
end
This converts your categories array to a string with your values separated by commas. It is not an array anymore. and it also removes "&commit=Submit" like you wanted.
If you dislike the rails routing method, you can also make your submit button to run some JS functions that builds the url string as you want it. For example <%= submit_tag , :onclick => "return buildUrl();" %>
Having this said, I must say I agree with Edward's comment, the url encoded format is standard and works out of the box, no need for all the additional rerouting and parsing. Im pretty sure whatever you need the data for can be used with the URL encoded format with proper parsing.

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 });
});`

Make a Select Box that Calls a Method

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.

How to display Rails select field values rather than stored integers in other views

I'm using a select field in a Rails app that is NOT tied to a related model, but stores integer values for a static series of options , i.e.,
<%= select (:this_model, :this_field, [['Option1',1],['Option2',2],['Option3',3],['Option4',4]] ) %>
In a show/ index view, if I want to display the option text (i.e. Option1, Option2, etc) rather than the integer value stored in the database, how do I achieve this?
Thanks for helping a noob learn the ropes!
EDIT
Based on Thorsten's suggestion below, I implemented the following. But it is returning nil, and I can't figure out why.
Invoice model:
##payment_status_data = { 1 => "Pending Invoice" , 2 => "Invoiced" , 3 => "Deposit Received", 4 => "Paid in Full"}
def text_for_payment_status
##payment_status_data[payment_status]
end
Invoice show view:
Payment Status: <%= #invoice.text_for_payment_status %>
In the console:
irb > i=Invoice.find(4)
=> [#<Invoice id: 4, payment_status: 1 >]
irb > i.text_for_payment_status
=> nil
I've tried defining the hash with and without quotes around the keys. What am I missing?
something like this would work:
<%= form_for #my_model_object do |form| %>
<%= form.label :column_name "Some Description" %>
<%= form.select :field_that_stores_id, options_for_select({"text1" => "key1", "text 2" => "key2"}) %>
<% end %>
Update
If you later want to display the text you can get it from a simple hash like this:
{"key1" => "text 1", "key2" => "text2"}[#my_object.field_that_stores_id]
But you better store this hash somewhere in a central place like the model.
class MyModel < ActiveRecord
##my_select_something_data = {"key1" => "text 1", "key2" => "text2"}
def text_for_something_selectable
##my_select_something_data[field_that_stores_id]
end
end
Then you can use it in your views like
#my_object.text_for_something_selectable
There are many possible variations of this. But this should work and you would have all information in a central place.
Update
Ok, I used something similar for our website. We need to store return_headers for rma. Those need to store a return reason as a code. Those codes are defined in an external MS SQL Server Database (with which the website exchanges lots of data, like orders, products, and much more). In the external db table are much more return reasons stored than I actually need, so I just took out a few of them. Still must make sure, the codes are correct.
So here goes he model:
class ReturnHeader < AciveRecord::Base
##return_reason_keys = {"010" => "Wrong Produc",
"DAM" => "Damaged",
"AMT" => "Wrong Amount"}
def self.return_reason_select
##return_reason_keys.invert
end
def return_reason
##return_reason_keys[nav_return_reason_code]
end
end
Model contains more code of course, but that's the part that matters. Relevant here is, that keys in the hash are strings, not symbols.
In the views i use it like this:
In the form for edit:
<%= form_for #return_header do |form| %>
<%= form.label :nav_return_reason_code "Return Reason" %>
<%= form.select :nav_return_reason_code, options_for_select(ReturnHeader.return_reason_select, #return_header.nav_return_reason_code) %>
<% end %>
(Maybe no the most elegant way to do it, but works. Don't know, why options_for_select expects a hash to be "text" => "key", but that's the reason, why above class level method returns the hash inverted.)
In my index action the return reason is listed in one of the columns. There I can get the value simply by
#return_headers.each do |rh|
rh.return_reason
end
If you have trouble to get it run, check that keys a correct type and value. Maybe add some debug info with logger.info in the methods to see what actual data is used there.

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