Simple Search with Rails - Search Results on Separate Page - postgresql

Im starting out in rails and trying to incorporate a simple search but am only getting so far.
the string looks ok but doesn't seem to execute to the results page. there seems to be a number of issues nil methods, actions missing or routes falling over when I try include restful resources.
I want search on one page (search) and the results to populate to another results page (map).
Both come under the PagesController and are actions within it.
The table is called towns and the user entries and CRUD area it is controlled by the TownsController and has an association with devise User_id.
There is then the pages controller which has search,map,about,contact pages.
class PagesController < ApplicationController
def index
end
def search
#towns = Town.search(params[:search])
end
def page
end
def map
end
end
--------------------------
class Town < ActiveRecord::Base
geocoded_by :name
after_validation :geocode
belongs_to :user
def self.search(search)
if search
search_condition = "%" + search + "%"
where(['townName LIKE ? OR townDescription LIKE ?', search_condition, search_condition])
end
end
-------------------------
views
search.html.erb
<div class="form-group">
<%= form_tag(pages_map_path , method: "get") do %>
<p>
<%= text_field_tag :search, params[:search], class: 'search-text' %>
<%= submit_tag "Search", :name => nil, class: 'btn btn-primary btn-lg'%>
</p>
<% end %>
results --> to map page
map.html.erb
<ul>
<% #towns.each do |town| %>
<li><%= link_to town.name,
:action => 'map', :id => town.id %></li>
<% end %>
</ul>
---------------------------
routes
Rails.application.routes.draw do
devise_for :users
get "pages/search"
get "pages/index"
get "pages/contact"
get "pages/about"
get "pages/map"
get "pages/page"
match ':controller(/:action(/:id))', :via => [:get, :post]
root 'pages#search'
end

Solution:
Column names in search query were incorrect
townName LIKE ? OR townDescription should be = name LIKE ? OR description
updated results page call to:
<ul>
<% #towns.each do |town| %>
<h2><li><%= link_to #name, controller: 'towns', :action => 'show', :id => town.id %></li></h2>
<% end %>
</ul>

Related

rails, form select, pluck 2 fields

I'm trying to simply display 2 fields (first name and last name) in a form select (f.select). Here is my code:
<%= f.select :person, User.where(verified_person: 't').pluck(:first_name, :last_name) %>
With the code above, the select drop-down field only displays first name. I'm using Active Record 4.2 and Rails 4. Any help?
Try Using This Code:
<%=f.select :person, options_for_select(User.where(verified_person: 't').collect {|user| ["#{user.first_name} - #{user.last_name}", user.first_name] }), :include_blank => true%>
I ended up using this.. seems to work for me:
<%= f.select(:person) do %>
<% User.where(verified_person: 't').each do |user| -%>
<%= content_tag(:option, user.first_name + " " + user.last_name, value: user.id) %>
<% end %>
<% end %>

Devise Registration not showing "some" nested form fields Rails 4

I've got a modified Devise "sign_up" form (new registration) that includes fields for child and grandchild objects to be created along with the user. All of the model relationships are set up properly with access to the child's attributes. However, when the form renders, only the fields for the Devise user and one of the grandchildren is shown.
When a User is created, he/she will automatically be assigned a Customer object, an Account object, and an Address object. As you can see by the relationships in the User model below, User has one Customer and Customer has many Accounts and one Address. There was previously an issue with rendering the form at all, which I solved by changing the values passed to the builder method. WHY WON'T THIS WORK??? This is what I have so far:
*user.rb
class User < ActiveRecord::Base
before_create :generate_id
# Virtual attribute for authenticating by either username or email
# This is in addition to a real persisted field like 'username'
attr_accessor :login
has_one :customer, :dependent => :destroy
has_many :accounts, through: :customer
accepts_nested_attributes_for :customer, :allow_destroy => true
accepts_nested_attributes_for :accounts, :allow_destroy => true
has_one :address, through: :customer
accepts_nested_attributes_for :customer, :allow_destroy => true
accepts_nested_attributes_for :address, :allow_destroy => true
has_one :administrator
validates_uniqueness_of :email, :case_sensitive => false
validates_uniqueness_of :id
validates :username,
:presence => true,
:uniqueness=> {
:case_sensitive => false
}
# User ID is a generated uuid
include ActiveUUID::UUID
natural_key :user_id, :remember_created_at
belongs_to :user
# specify custom UUID namespace for the natural key
uuid_namespace "1dd74dd0-d116-11e0-99c7-5ac5d975667e"
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :timeoutable, :recoverable, :trackable, :validatable
# Generate a random uuid for new user id creation
def generate_id
self.id = SecureRandom.uuid
end
# Allow signin by either email or username ("lower" function might have to be removed?)
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions.to_h).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
else
where(conditions.to_h).first
end
end
end
registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
# GET /users/sign_up
def new
#user = User.new
build_resource({})
self.resource[:customer => Customer.new, :account => Account.new, :address => Address.new]
respond_with self.resource
end
def create
#user = User.new
# Override Devise default behavior and create a customer, account, and address as well
resource = build_resource(params[:sign_up])
if(resource.save)
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
render :action => "new"
end
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u|
u.permit(:username, :email, :password, :password_confirmation,
customer_attributes: [:title, :firstname, :lastname, :phone1, :phone2],
account_attributes: [:acct_type],
address_attributes: [:address1, :address2, :zip_code])
}
end
end
application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :configure_permitted_parameters, if: :devise_controller?
def after_sign_in_path_for(resource)
if current_user.role == 'admin'
adminview_administrator_path(current_user, format: :html)
else
accounts_path(current_user, format: :html)
end
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation,
customer_attributes: [:title, :firstname, :lastname, :phone1, :phone2],
account_attributes: [:acct_type],
address_attributes: [:address1, :address2, :zip_code]) }
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:login, :username, :email, :password) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:username, :email, :password, :password_confirmation, :current_password) }
end
end
views/devise/registrations/new.html.erb
<h1>Create an account</h1>
<div class="panel panel-default" style="width: 50%; padding: 0 25px;">
<%= bootstrap_nested_form_for(resource, as: resource_name, url: user_registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<h3>User Info</h3>
<!-- fields for User object -->
<%= f.text_field :username, autofocus: true %>
<%= f.email_field :email %>
<%= f.password_field :password , autocomplete: "off"%>
<% if #validatable %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
<!-- fields for Customer object -->
<%= f.fields_for :customer do |customer_fields| %>
<%= customer_fields.text_field :title %>
<%= customer_fields.text_field :firstname %>
<%= customer_fields.text_field :lastname %>
<%= customer_fields.text_field :phone1 %>
<%= customer_fields.text_field :phone2 %>
<% end %>
<!-- fields for Account object -->
<%= f.fields_for :account do |account_fields| %>
<%= account_fields.text_field :acct_type %>
<% end %>
<!-- fields for Address object -->
<%= f.fields_for :address do |address_fields| %>
<%= address_fields.text_field :address1 %>
<%= address_fields.text_field :address2 %>
<%= address_fields.text_field :zip_code %>
<% end %>
<br />
<div class="actions">
<%= f.submit "Create My Account", :class => "btn btn-info" %>
</div>
<% end %>
</div>
</div>
Again, the above view does render, but the form only displays the fields for Devise new user and the one field (acct_type) for the account fields. How to get the rest of form to display and create all of these things on submission? Everything I've tried and everything I've read leads me to think that there's a problem with Rails 4's strong_parameters not being able to recognize the permitted attributes (see above controllers) in an array. Could that be the issue? If so, how does one go about passing the parameters necessary to build all these things?
Could be problem with the routes?
routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { :registrations => "registrations" }
devise_scope :user do
# authentication
post "/accounts/adminview" => "devise/sessions#new"
end
root 'home#index'
resources :administrators do
member do
get :adminview
end
end
resources :users do
resource :customers
resource :accounts
resource :addresses
end
resources :account_types, :accounts, :addresses, :administrators, :customers, :transaction_types, :transactions, :users
end
I've tried every combination of ways that I could find on SO. This has taken up days worth of valuable time. I don't see any reason why it can't work. Does anyone have a better way of doing this? Is there a gem that would help? I'm willing to tear Devise apart and rebuild if necessary.
F.Y.I. It's Rails 4 and Devise 3.4.1. I've also added nested_form gem, but it doesn't make a difference.
Thank you
If you raise your params in controller you probably see accounts_attributes instead account_attributes you are setting in permit at application_controller, try replace it.

Rails, choosing option in drop-down filters values in second drop-down

I'm trying to create some pages in my rails app, using bits and pieces of what I've learned from some Railscasts. My environment is as follows:
Rails 3.2.13
ruby 1.9.3p448
Using the chosen gem
Database SQLite
When I want to create a new profile, I would visit localhost:3000/profiles/new.
There I have a text box for my profile called Name. Next I have a drop-down
where the use can choose what profile type - Admin, Editor or User. Once an
option is selected, another drop-down becomes visible - Traits. The user can
then choose 1 or many traits.
For each profile type (Admin, Editor, User) there are different traits. So the
Traits model has fields name and trait_type where trait_type would have a value
of either Admin, Editor or User.
I'm having trouble coding the view, assuming I should code there, but maybe I
should be in a controller, getting the Traits drop-down to display only say
Admin traits if I choose a profile type of Admin.
Can someone please give me a nudge in a positive direction? Please keep in mind
that I'm new to this. Hope I am providing enough, and not too much information.
Note: The console.log entries in my profiles.js.coffee file is temporary, just
so I can see what is going on.
Thanks,
HoGi
-------------------------------------------------
/app/assets/javascripts/application.js
-------------------------------------------------
//= require jquery
//= require jquery_ujs
//= require chosen-jquery
//= require_tree .
-------------------------------------------------
-------------------------------------------------
/app/assets/javascripts/profiles.js.coffee
-------------------------------------------------
jQuery ->
$('#profile_trait_ids').chosen()
jQuery ->
$('#profile_trait_ids').parent().hide()
prof_types = $('#profile_prof_type').html()
console.log(prof_types)
$('#profile_prof_type').change ->
prof_type = $('#profile_prof_type :selected').text()
console.log(prof_type)
$('#profile_trait_ids').parent().show()
-------------------------------------------------
-------------------------------------------------
/app/assets/stylesheets/application.css
-------------------------------------------------
*= require_self
*= require chosen
*= require_tree .
*/
-------------------------------------------------
-------------------------------------------------
/app/models/profile.rb
-------------------------------------------------
class Profile < ActiveRecord::Base
attr_accessible :active, :name, :prof_type, :trait_ids
has_many :traitships
has_many :traits, through: :traitships
PROFILE_TYPES = ["Admin", "Editor", "User"]
end
-------------------------------------------------
-------------------------------------------------
/app/models/trait.rb
-------------------------------------------------
class Trait < ActiveRecord::Base
attr_accessible :active, :name, :trait_type
has_many :traitships
has_many :profiles, through: :traitships
end
-------------------------------------------------
-------------------------------------------------
/app/models/traitship
-------------------------------------------------
class Traitship < ActiveRecord::Base
#attr_accessible :profile_id, :traid_id
belongs_to :profile
belongs_to :trait
end
-------------------------------------------------
-------------------------------------------------
/app/views/_form.html.erb
-------------------------------------------------
<%= form_for(#profile) do |f| %>
<% if #profile.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#profile.errors.count, "error") %> prohibited this profile from being saved:</h2>
<ul>
<% #profile.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :prof_type, 'Profile Type' %><br />
<%= f.select :prof_type, Profile::PROFILE_TYPES, prompt: 'Select a type' %>
</div>
<div class="field">
<%= f.label :trait_ids, "Traits" %><br />
<%= f.collection_select :trait_ids, Trait.order(:name), :id, :name, {}, { multiple: true } %>
</div>
<div class="field">
<%= f.label :active %><br />
<%= f.check_box :active %>
</div>
<div class="actions">
<%= f.submit 'Update' %>
</div>
<% end %>
-------------------------------------------------
UPDATED CONTROLLER:
(traits_controller)
# GET /traits/:trait_type/trait_options
# GET /traits/:trait_type/trait_options.json
def trait_options
#traits = Trait.order(:name).where("trait_type like ?", params[:trait_type])
respond_to do |format|
format.html # trait_options.html.erb
format.json { render json: #traits }
end
end
Part 1
You should add a new action to your controller (traits_controller) that takes as input one parameter profile_type and returns all traits for that profile_type as json/xml.
Part 2
Once you have this ready, You should call this action via ajax on on_change event of your profile_type dropdown. Use that data received to construct the new traits dropdown.
chosen, select2 etc, should make this very easy to accomplish once your part 1 is ready.
Update
I have never used chosen myself. But looking at its documentation, something like this might work for you
$('#profile_type').on('change', function() {
$("#traits").chosen().change( … );
$("#traits").trigger("chosen:updated");
});
This Railscast (Episode #258) demonstrates how a chosen select is populated using json data
If it is possible to drop chosen in favor of select2, I highly recommend you do it.

Setting up sunspot geolocation scenario

I am using Sunspot for searching and using Geocoder for addresses and then for calculating distances, Geokit-rails3.
class Product < ActiveRecord::Base
belongs_to :store
searchable do
text :name
end
end
class Store < ActiveRecord::Base
acts_as_mappable
geocoded_by :address, :latitude => :lat, :longitude => :lng
attr_accessible :lat, :lng, :address
has_many :products
end
Question
What I want when typing in a product to search for is also the ability to type an address inside of another field to search for products in that given area with a 30 mile radius.
This is my controller which allows me to search for Products:
class SearchController < ApplicationController
def index
#search = Product.search do |q|
q.fulltext params[:search]
end
#products = #search.results
end
end
So I believe the form would look something like this after I am done:
<%= form_tag search_path, :method => 'get' do %>
<%= text_field_tag :search, params[:search]" %>
<%= submit_tag "Search", :name => nil %>
<p> Search Near: </p>
<%= label_tag :location, "Search nearby an Address" %>
<%= text_field_tag :location, params[:location] %>
<% end %>
I am thinking :location would serve as a virtual attribute for the Stores :address in order for the field to be mapped correctly but this is all speculation.
How do I set this all up in order to achieve the specific scenario?

Rails 3 fields_for different layout for existing records/new records, file uploads

I have a Content model which has one or many Audio files which need to be added by the new/edit form.
What I have did is created the models with this relationship:
class Audio < ActiveRecord::Base
belongs_to :content
has_attached_file :audiofile,
end
class Content < ActiveRecord::Base
...
has_many :audios
accepts_nested_attributes_for :audios, :allow_destroy => true
end
Now in my new Content form I have the following:
<% f.fields_for :audios do |audiof| -%>
<%= f.label :audiofile, 'Audio file:' %>
<%= audiof.file_field :audiofile %>
<% end -%>
What I need it to do is show me the file_field only for a new Audio file and for the existing ones just print me a file size,name and probably a delete button.
I have also created a new record in the controller with:
#content.audios.build
I am using Rails 3.0.3 with Paperclip plugin for upload. Sorry if the question is too nooby.
Thanks.
From my memory, you will be able to access to the instance of the object within the fields_for statement.
Try something like that :
<% f.fields_for :audios do |audiof| -%>
<% if audiof.object.new_record? %>
<%= f.label :audiofile, 'Audio file:' %>
<%= audiof.file_field :audiofile %>
<% else %>
<%= "Filename = #{audiof.object.audiofile.filename}" %>
<%= "url = #{audiof.object.audiofile.url}" %>
<% end %>
<% end -%>
If audiof.object returns nil(In that case, it is not the good name), check by displaying all the public methods <% = raise audiof.public_methods.inspect %>
The object method should return an instance of an Audio class.