How to save search preferences to database - ruby-on-rails

I have a advanced search form and I wanted to know how can I save the user selections to the database. The current setup saves each search performed to the database, thus allowing me to have statistics of what users are searching for on the website.
The question I have is how can I save that users selections to their account so that it preloads when they return to the website, or they can create lists of saved search options. I have a social networking app so this would be helpful to the User so that they do not have to enter the age range, zip code, etc each time they visit the website.
I'm not sure how to do this.
Searches controller:
def new
#search = Search.new
end
def create
#search = Search.new(params[:search])
if #search.save
redirect_to #search
else
render 'new'
end
end
def show
#search = Search.find(params[:id])
#users = #search.users
end
Search model:
def users
#users ||= find_users
end
private
def find_users
users = User.order(:id)
users = users.where(gender: gender) if gender.present?
users = users.where(zip_code: zip_code) if zip_code.present?
users = users.where(children: children) if children.present?
users = users.where(religion: religion) if religion.present?
users = users.where(ethnicity: ethnicity) if ethnicity.present?
if min_age.present? && max_age.present?
min = [ min_age, max_age ].min
max = [ min_age, max_age ].max
min_date = Date.today - min.years
max_date = Date.today - max.years
users = users.where("birthday BETWEEN ? AND ?", max_date, min_date)
users
end
users
end
end
Search form:
<%= form_for #search do |f| %>
<div class="field">
<%= f.label :gender %><br />
<%= f.select :gender, ['male', 'female'], :include_blank => true %>
</div>
<div class="field">
<%= f.label :zip_code %><br />
<%= f.text_field :zip_code %>
</div>
<div class="field">
<%= f.label :children %><br />
<%= f.select :children, [['Yes, they live with me'], ['I want kids now'], ["I want one someday"], ["Not for me"]], :include_blank => true %>
</div>
<div class="field">
<%= f.label :religion %><br />
<%= f.select :religion, [["Agnostic"], ["Atheist"], ["Christian"], ["Catholic"], ["Buddhist"], ["Hindu"], ["Jewish"], ["Muslim"], ["Spiritual without affiliation"], ["Other"], ["None"], ["Prefer not to say"]], :include_blank => true %>
</div>
<div class="field">
<%= f.label :ethnicity %><br />
<%= f.select :ethnicity, [["Asian"], ["Biracial"], ["Indian"], ["Hispanic/Latin"], ["Middle Eastern"], ["Native American"], ["Pacific Islander"], ["White"], ["Other"]], :include_blank => true %>
</div> <%= f.select :min_age, (18..75), :include_blank => true %>
to
<%= f.select :max_age, (18..75), :include_blank => true %>
<div class="actions"><%= f.submit "Search" %></div>
<% end %>

you can use json, marshal or any other serializers to serialize the search params as a string ,then store it into the cookie or database.

You could store the search settings in the session. The drawback is that when a client visits the site from a different computer or browser, there are no saved search settings, because the session id is stored in a cookie.
If you really want the settings persisted in the database, you could create a search_settings field on the User model and serialize the settings to this field. If you are using Postgresql you could use the array or hstore column type.

Related

Multiple select in administrate

Since administrate does not yet have support for multiple selects. Has anyone created a custom multiple select? Preferably one that works like the HasMany select.
Here it is in case someone else needs it:
app/fields/multiple_select_field.rb
# app/fields/multiple_select_field.rb
require "administrate/field/base"
class MultipleSelectField < Administrate::Field::Select
def to_s
data
end
def self.permitted_attribute(attribute)
{ attribute.to_sym => [] }
end
def permitted_attribute
self.class.permitted_attribute(attribute)
end
end
app/views/fields/multiple_select_field/_form.html.erb
# app/views/fields/multiple_select_field/_form.html.erb
<div class="field-unit__label">
<%= f.label field.attribute %>
</div>
<div class="field-unit__field">
<%= f.select(
field.attribute,
options_from_collection_for_select(
field.selectable_options,
:to_s,
:to_s,
field.data.presence,
),
{}, multiple: true,
) %>
</div>
app/views/fields/multiple_select_field/_index.html.erb
# app/views/fields/multiple_select_field/_index.html.erb
<%= field.to_param.join(', ') %>
app/views/fields/multiple_select_field/_show.html.erb
# app/views/fields/multiple_select_field/_show.html.erb
<%= field.to_param.join(', ') %>

How do I select a car make and then select model according to make?

In my rails project I have two models, Car Make & Car Model, with a 1:M relationship (i.e. one Audi has many Audi models).
In my Views page, I want a form with two input fields for car make & car model. Ideally, I will be able to input a car make (i.e. Audi) and the second input field will have a drop down menu with all the models available for the make (2016 Audi A6, 2017 Audi A7).
I've set up all the relations and in the models I have saved a foreign key of the make.
currently in _form.html.erb I have
<div class="field">
<%= f.label :make_id, "Make:"%><br>
<%#= f.number_field :make_id %>
<%= f.collection_select :make_id, Make.all,
:id,:makes_info, {:include_blank => 'Please Select'} %>
</div>
<div class="field">
<%= f.label :model_id, "Model:" %><br>
<%= f.collection_select :model_id, Model.all,
:id,:model_info, {:include_blank => 'Please Select'} %>
</div>
If you want it to truly be dynamic, you would need to use an AJAX request to update the second select after the first is picked. You'd also need to use the options_for_select method inside of the select tag
Some more info to accompany what was already provided.
It's known as dynamic select boxes:
#config/routes.rb
resources :makes do
get :models, on: :collection #-> url.com/makes/models
end
#app/controllers/makes_controller.rb
class MakesController < ApplicationController
def models
#make = Make.find(params[:make][:make_id])
respond_to do |format|
format.js
end
end
end
#app/views/makes/models.js.erb
$select = $("select#models");
$select.empty();
<% #make.models.each do |model| %>
$select.append($('<option>').text(<%=j model.name %>).attr('value', <%= model.id %>));
<% end %>
#views
<%= f.collection_select :make_id, Make.all, :id, :makes_info, {include_blank: 'Please Select'}, { data: { remote: true, url: make_models_path }} %>
<%= f.collection_select :model_id, Model.all, :id,:model_info, {include_blank: 'Please Select'}, { id: "models" } %>

Problems using form helpers in ruby on rails

I have a class activity that has the follow atributes:
String type, Date date, String title
By including the associations it also has user_id and place_id.
class Activity < ActiveRecord::Base
belongs_to :user
belongs_to :place
In the other side User has many activities and place has many activities
So, the problem is when I want to create a new activity:
Scaffold creates the helper _form :
<%= form_for(#activity) do |f| %>
<% if #activity.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#activity.errors.count, "error") %> prohibited this activity from being saved:</h2>
<ul>
<% #activity.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :type %><br>
<%= f.text_field :type %>
</div>
<div class="field">
<%= f.label :date %><br>
<%= f.datetime_select :date %>
</div>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :user_id %><br>
<%= f.number_field :user_id %>
</div>
<div class="field">
<%= f.label :place_id %><br>
<%= f.number_field :place_id %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I want to receive the first 3 fields from the form (type, date and title) but to associate a user and a place I have to do other way. I need the user that is actual logged in and the place is choosen by tiping the name.
My idea to do this is the following:
1) The user issue, I can make a query by using the current_logged_user that I have acess and get his ID.
2) The place issue, I can use the name that I receive from form and query my Places table for the place with the name X and get the ID after.
But, because I don't know too much about rails, how can I do this? How can I use f.text_field and then made the query or whatever and use after in the controller?
Controller has already this stuff :
def create
#activity = Activity.new(activity_params)
(...)
private
# Use callbacks to share common setup or constraints between actions.
def set_activity
#activity = Activity.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def activity_params
params.require(:activity).permit(:type, :date, :title, :user_id, :place_id)
end
You can structure your rails app to get neither the user_id nor the place_id directly from the form. Especially getting user_id from a submitted form is generally not a good idea. You usually do not want to whitelist user_id at all.
For user_id:
If you are using a gem like devise for user authentication, it gives you access to a method called current_user, which you can use to set the user_id from.
For place_id:
I suggest putting the activity as a sub route of place. e.g. instead of having the form under <host>/activities/new, put it under ``/places/:place_id/activities/new`. In your route file put the route as follows:
resources :places do
resources :activities
end
Now, in your controller action you can do the following:
def create
#activity = current_user.activities.new(activity_params)
#activity.place_id = params[:place_id] (or even safer will be #activity.place = Place.find(params[:place_id], but this will require one more sql query )
(...)
private
# Never trust parameters from the scary internet, only allow the white list through.
def activity_params
params.require(:activity).permit(:type, :date, :title)
end
UPDATE:
If you absolutely want to have the form under /activities/new route then you can have a select tag for place_id in your form:
select_tag 'activity[place_id]', options_from_collection_for_select(Place.all, 'id', 'name')
This will create a selection with name 'activity[place_id]' (named this way for params.require(:activity).permit(place_id) ) and options looking like
<option value="1">Barcelona</option>

Ruby on rails drop down box Beginner lvl

So I am a beginner in ROR, like I know it for a month (school assignment and we don't get a cursus we need to use 'google')
So I want a dropdown box with a list of all my cities. Then if I pick a city I need to save the city_id in my database together with the date. The code I have so far seem to work except when I click on save it says that city is empty (and it can't be empty because of the failsave)
this is my code
<div class="field">
<%= f.label :stad_id %><br />
<% cities_array = Stad.all.map { |stad| [stad.naam, stad.land] } %>
<%= select_tag(Stad, options_for_select(cities_array)) %>
</div>
<div class="field">
<%= f.label :datum %><br />
<% datum = Time.now.to_s(:db) %>
<%= f.text_field :datum, :value => datum.inspect, :readonly => true %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I don't really know what I am doing wrong except I have an eery feeling I don't actually give the command to save it.
help is much thanked
sincerely
Robin
There are a few things I notice here that are wrong.
1) Put the creation of the cities_array into your controller, not in your view:
def edit
#something = Something.find(params[:id])
#cities_array = ... whatever ...
end
2) When creating your cities_array, you need to specify the ID of the city as the second parameter, like this:
#cities_array = Stad.all.map { |stad| [stad.naam, stad.id] }
3) The select_tag call isn't for Stad, it's for the model you're trying to save. For example, your form might look like this:
<%= form_for #something %>
<%= f.label :city %>
<%= f.select :city_id, #cities_array %>
# or!
<%= select :something, :city_id, #cities_array %>
<% end %>
I hoep this clears things up for you.

Two records with two different layouts/views in one create

Ok, here my Problem:
i have a tabel in a radius-system. to enable a hotspot-user i need two different records in this table.
the record has the fields user, attr, op, value
first record: attribute has to be Password (this record is only for the password here) and value is the password itself.
second record: attribute has to be something like Max-Allowed-Session an value is an integer in seconds.
So i add this as nested attributes to my controller clients. In new i do that:
def new
#client = Client.new
2.times do
radcheck = #client.radchecks.build
end`
respond to........
end`
Ok, in my view i have this at the moment:
f.fields for :radchecks do |rcbuilder|
<p><%= rcbuilder.label :username %><br /><%= rcbuilder.text_field :username %>
for all fields .....
end
In my controller i built two radchecks, so this part is shown two times.
That is status, but i wanna have something like this in my website
<first occurence of that form>
<%= rcbuilder.hidden_field :attr, :value => "password" %>
<%= rcbuilder.hidden_field :value, :value => #generated_password %>
<end first occurence>
<second occurence of that form>
<%= rcbuilder.hidden_field :attr, :value => "Max-Allowed-Session" %>
<%= rcbuilder.label :value, 'Time in hours' %><%= rcbuilder.text_field :value %>
<end second occurence>
Somone has an idea to realize that. Maybe i have to write the indexed fields myself, but how can i achieve that?
thanks for help....
Assuming you are using accepts_nested_attributes_for :radchecks in your Client model.
<% index=1 %>
f.fields for :radchecks do |rcbuilder|
<%= render :partial=>'radcheck_fields', :locals=>{:rcbuilder=>rcbuilder, :index=>index}%>
<% index+=1 %>
end
Next create a partial named radcheck_fields.html.erb with the following code.
<% if index.eql?(1) %>
<%= rcbuilder.hidden_field :attr, :value => "password" %>
<%= rcbuilder.hidden_field :value, :value => #generated_password %>
<% else %>
<%= rcbuilder.hidden_field :attr, :value => "Max-Allowed-Session" %>
<%= rcbuilder.label :value, 'Time in hours' %><%= rcbuilder.text_field :value %>
<% end %>

Resources