I have a simple dropdown that I want to populate from a model. I don't want to bind it to another model at all, just a simple standalone form with a list of items and handle storing the state of the dropdown in a session variable, I can achieve it with a more brute force approach as shown but it doesn't feel very 'rails' to me.
<form action='/home/switch' method='post'>
<select name="all_items">
<% #items.each do |i| %>
<option value="<%= i.id %>" <%= i.id.to_s == session[:current_item] ? "selected" : "" %>><%= i.name %></option>
<% end %>
</select>
<input type="submit">
</form>
Is there a better way to do this in Rails?
Update: Yep. collection_select worked for me:
<%= collection_select(:item, :id, Item.all, :id, :name, {:selected => session[:current_item].id}) %>
Take a look at form_tag, select_tag, options_from_collection_for_select, and/or collection_select.
So your example might look like this (not tested, may have typos)
<%= form_tag('/home/switch') do %>
<%= select_tag('all_items', options_from_collection_for_select(#items, 'id', 'name')) %>
<%= submit_tag %>
<%= end %>
This is missing the "selected" bit, take a look at the docs for that.
Related
In my index view, I'm iterating over a list of bookings.
Also, I added a dropdown menu with the option to sort by created_at: asc and created_at: desc.
index.html.erb
<div class="dropdown">
<button class="btn" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Sort by
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<p> <%= link_to "ASC", sort: :asc %> </p>
<p> <%= link_to "DESC", sort: :desc %> </p>
</div>
</div>
<% #bookings.each do |booking| %>
<%= booking.address %>
<%= booking.created_at %>
<% end %>
This is the way I am sorting the #bookings in the controller:
booking_controller.rb
class Users::BookingsController < ApplicationController
def index
#bookings = current_user.bookings.order(created_at: params[:sort])
end
end
I'm not really sure if this is the best solution and if it has some vulnerability in terms of SQL injections...
Generally using params for order is unsafe, see https://rails-sqli.org/#order
You can use sanitize_sql_for_order to sanitaze input for ActiveRecord#order
Passing key/value pairs to order(created_at: params[:sort]) is safe. Rails validates the direction. If you give it an invalid direction it will raise ArgumentError: Direction "..." is invalid. It's been this way since the syntax was introduced in Rails 4.
Passing a string to order as in order("created_at #{params[:sort]}") could be exploited in Rails 5 and earlier. See Rails SQL Injection for details. Rails 6 now sanitizes order arguments and will raise an exception if it detects funny business.
Rails 6, in general, is more robust against SQL injection. But it's up to you to sanitize your inputs before passing them to anything which accepts raw SQL.
Your view is not turning the bookings into a drop down menu. Instead, it's just a bunch of text. As lurker suggested, use a function like collection_select to generate the select and option tags for you.
<%= form_for #user do |f| %>
<%= f.collection_select :booking_id, #bookings, :id, proc { |b| "#{b.address} #{b.created_at}" , prompt: true %>
<%= f.submit %>
<% end %>
To tidy that up a bit, you can add a method to Booking to produce the label you want and replace the proc.
class Booking
def dropdown_value
"#{address} #{created_at}"
end
end
<%= form_for #user do |f| %>
<%= f.collection_select :booking_id, #bookings, :id, :dropdown_value, prompt: true %>
<%= f.submit %>
<% end %>
I have a page in my rails application that shows a list of listings (paginated using will_paginate). I am trying to find a good gem to implement searching and sorting with the list on this page. The Ransack gem looked like what i needed but i'm running into an issue with it. This is what my code looks like right now with the Ransack gem.
My model (didn't include the whole model, didn't want the validations and extra code to get in the way):
UNRANSACKABLE_ATTRIBUTES = ["id", "state", "show_email", "email", "show_phones", "primary_phone", "secondary_phone", "updated_at", "user_id"]
def self.ransackable_attributes auth_object = nil
(column_names - UNRANSACKABLE_ATTRIBUTES) + _ransackers.keys
end
My controller action:
def index
#search = Listing.search(params[:q])
#listings = #search.result.paginate(page: params[:page], per_page: 20, joins: "LEFT OUTER JOIN attachments ON listings.id = attachments.attachable_id", select: "listings.*, COUNT(attachments.id) AS photos", group: "listings.id", order: "listings.created_at DESC, listings.title ASC, listings.id DESC")
#search.build_sort if #search.sorts.empty?
end
My search form on the page:
<div class="advanced-search">
<%= search_form_for #search do |f| %>
<div class="search-by">
<div class="search-field">
<%= f.label :title_cont, "Title Contains" %>
<%= f.text_field :title_cont %>
</div>
<div class="search-field">
<%= f.label :description_cont, "Description Contains" %>
<%= f.text_field :description_cont %>
</div>
<div class="search-field">
<%= f.label :price_gteq, "Price Between" %>
<%= f.text_field :price_gteq %>
<%= f.label :price_lteq, "and" %>
<%= f.text_field :price_lteq %>
</div>
</div>
<div class="sort-by">
<%= f.sort_fields do |s| %>
<%= s.sort_select %>
<% end %>
</div>
<div class="search-actions">
<%= f.submit "Search" %>
</div>
<% end %>
</div>
My route:
resources :listings do
collection do
match 'search' => 'listings#index', via: [:get], as: :search
end
end
With everything i have in place now i have been able to get the application to successfully search and sort the listings.
My question: The sort_select field is showing everything option that is "ransackable". Is there a way to make one attribute available for the searching, but not the sorting? For example i want the ability to search on the description attribute but it doesn't make any sense to include that attribute in the sorting. How can i use an attribute in one and not the other? Thanks for any help and let me know if my question is not clear enough.
Couldn't figure out how to get the values i wanted into the dropdown so i just used links instead. Here's what i ended up with for the sorting.
Sort by <%= sort_link #search, :title %> | <%= sort_link #search, :price %> | <%= sort_link #search, :created_at, "Date Listed" %>
I have a Rails form, where I am trying to insert a Select formfield .
My current code runs like this -
<select id="selectservice" name="service">
<% #categories.each do |category| %>
<% #services= category.services %>
<% #services.each do |service| %>
<option value="<%= service.id %>"><%= service.name %></option>
<% end %>
<% end %>
</select>
Now I want to convert this into a Formbuilder style as the rest of the form is in that style . And also I will be able to insert the variable which is missing here . How do I go about inserting the option tags ?
<%= form_for #appointment do |f| %>
<%= f.select :service_id, :name=>"service" %>
##How do I insert the Option tags here ?
<%= end %>
I think I found the answer . This can be achieved by Grouped Options for Select
<%= f.grouped_collection_select :service_id,
#categories, :services, :name,
:id, :name , :id=>"selectservice"
%>
I have seen a few posts here about searching across multiple models (here and here, in particular). However, I'm wondering if I can adapt Ryan's Railscast #37 to do this for three or four models without having to figure out Thinking Sphinx as I'm a beginner to all this.
As I said I have a few models, although I only reference two for brevity below, and I made a searches_controller with index and show actions.
On the models I included Ryan's model code:
def self.search(search)
if search
find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
else
find(:all)
end
end
And in the searches_controller I have the following:
def index
#profiles = Profile.search(params[:search])
#employers = Employer.search(params[:search])
end
def show
#profiles = Profile.search(params[:search])
#employers = Employer.search(params[:search])
end
In my searches/show.html.erb I have the following:
<%= #profiles.each do |profile| %>
<div class="question">
<div class="questionHeader">
<h5 class="questionTitle"><%= link_to profile.first_name, profile %></h5>
</div>
</div><!-- end question -->
<% end %>
<%= #employers.each do |employer| %>
<div class="question">
<div class="questionHeader">
<h5 class="questionTitle"><%= link_to employer.name, employer %></h5>
</div>
</div><!-- end question -->
<% end %>
When I perform the search, my show renders what looks like three empty arrays [][][].
Without ditching this and moving to Thinking Sphinx is there anything I can do to get this working using the simple form below?
<% form_tag searches_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "#", :name => nil %>
</p>
<% end %>
I wrote a form that generates a text input for each property.
The list of properties is configurable by the customer.
<% properties = ["refractivity_at_2kHz", "refractivity_at_5kHz"] %>
<% properties.each do |property| %>
<div class="property">
<%= f.label property %>
<%= f.text_field property %>
</div>
<% end %>
It fails with the error undefined method refractivity_at_2kHz.
What is the usual solution for this problem?
Should I add an array to my model, and use f.text_field myarray[property] ?
Is it a form_for(#model)?
Because then f.text_field(property) looks for that method/property on #model.
May be you want to change f.text_field(property) into text_field_tag(property)[1]
cheers
[1] http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-text_field_tag