Sunspot/Solr : Searching with multiple fields - ruby-on-rails

What is the way to use Sunspot/Solr with mutiple fields ?
It works fine with a simple form, as explained in this screencast : http://railscasts.com/episodes/278-search-with-sunspot
You can see my draft which doesn't work :
product.rb
searchable do
text :address
text :model
text :category
end
*products_controller.rb*
def search
#search = Sunspot.search(Product) do
fulltext params[:address]
with(:model, params[:model]) if params[:model].present?
with(:category, params[:category]) if params[:category].present?
end
#products = #search.results
end
products/search.html.erb
<%= form_tag products_search_path, :method => :get do %>
<div class="field">
<%= label_tag "Address ?" %>
<%= select_tag :address, "<option>he</option><option>ho</option>".html_safe %>
</div>
<div class="field">
<%= label_tag "Model ?" %>
<%= text_field_tag :model, params[:model] %>
<%#= select_tag :model, "<option>hi</option><option>ha</option>".html_safe %>
</div>
<div class="field">
<%= label_tag "Category ?" %>
<%= text_field_tag :category, params[:category] %>
</div>
<div id="buttonSearch"><%= submit_tag "Search" %></div>
<% end %>
The error :
Sunspot::UnrecognizedFieldError (No field configured for Product with name 'model'):
app/controllers/products_controller.rb:99:in `block in search'
app/controllers/products_controller.rb:97:in `search'
Thanks guys for your helping!

You only want this (below)... You only want full text, which will search across all fields you define in searchable... I used "s" as the param name
#search = Sunspot.search(Product) do
fulltext(params[:s])
end

If you setup product.rb like so (specifying :model and :category as non-fulltext string fields that can be used for scoping), then your search code should work verbatim.
# product.rb
searchable do
text :address
string :model
string :category
end

Related

loop on a select input ruby on rails

I'm trying to make a select input on all my users in ruby on rails, that almost works but the thing is that the don't get the username of my user but i render somethings like this : #<User:0x007f8cc1024d60>
I created 3 users in my console, I can see them while i'm on rails console
I got this in my controller :
def new
#bug = Bug.new
#users = User.all
end
Also my params
def bug_params
params.require(:bug).permit(:owner, :title, :description)
end
And in my html :
<%= form_with model: #bug do |form| %>
<%= form.select :owner, #users %>
<%= form.text_field :title, placeholder: "title" %>
<%= form.text_area :description, placeholder: "description" %>
<%= form.submit %>
<% end %>
Could someone explain me what's wrong ?
With your select form helper, you return only a collection of User instances.
As specified in the documentation, you need to collect what attribute of User you want to pass as option value and option display.
For example:
<%= form.select :owner, #users.collect {|u| [ u.name, u.id ] } %>
#=> output
# <select name="bug[owner]">
# <option value="1">John</option>
# <option value="2">Joe</option>
# </select>
Use collection_select to create a select from a collection of records.
<%= form_with model: #bug do |form| %>
<%= form.collection_select(:owner, #users, :id, :name) %>
<%= form.text_field :title, placeholder: "title" %>
<%= form.text_area :description, placeholder: "description" %>
<%= form.submit %>
<% end %>

Ruby on Rails: Keep check boxes selected after search

In my RoR application I have a form whereby users can search for their contacts by first name and select the ones that they want to send an email to. My problem is that after searching for say "Tom", and selecting the checkbox for "Tom", if they then reset the search to display all check boxes "Tom" is no longer selected.
Can someone please tell me how this can be sorted?
The code in the view is:
<div class="panel-body">
<%= form_tag '/emails/contact_search', :method => 'get' do %>
<p>
<%= text_field_tag :search_string, params[:search_string], :placeholder => "Search by firstname" %>
<%= submit_tag "Search" %>
</p>
<% end %>
<%= form_for(#email) do |f| %>
<fieldset>
<div class="form-group">
<label>From Email Address</label></br>
<% #useraccounts.each do |useraccount| %>
<%= f.radio_button :account_id, useraccount.account_id, :checked => false %>
<%= f.label :account_id, useraccount.account.email, :value => "true" %><br>
<% end %>
</div>
<div class="form-group">
<label>Contacts</label></br>
<%= f.collection_check_boxes :contact_ids, #contacts, :id, :fullname, checked: #selected_contact_ids %>
</div>
<div class="form-group">
<label>Groups</label></br>
<%= f.collection_check_boxes :group_ids, Group.where(user_id: session[:user_id]), :id, :name ,{ prompt: "name" } %>
</div>
<div class="form-group">
<label>Attachment</label>
<%= f.file_field :attachment, :size => 42 %><br>
</div>
<div class="actions">
<%= f.submit "Continue", {:class => 'btn btn-primary '} %>
<%= render "/error_messages", :message_header => "Cannot save: ", :target => #email %>
</div></br>
</fieldset>
<% end %>
</div>
The controller code for the search is:
def contact_search
#email = Email.new(session[:email_params])
#email.current_step == session[:email_step]
#useraccounts = Useraccount.where(user_id: session[:user_id])
#contacts = Contact.contact_search(params[:search_string])
if #contacts.empty?
flash[:notice] = "There are no emails with that subject"
#contacts = Contact.all
end
render :action => "new"
end
private
def email_params
params.require(:email).permit(:subject, :message, :account_id, { contact_ids: [] }, { group_ids: [] }, :attachment)
end
And in the model:
def self.contact_search(search_string)
self.where("firstname LIKE ?", search_string)
end
I cannot work out how to keep a checkbox selected after a user then searches for something else or resets the search, can someone please shed some light on how this can be achieved?
This seems to be one of those obscure and badly documented features of Rails. What has to be done is pass an array if ids to be checked into the checked parameter
= f.collection_check_boxes :contact_ids, #contacts, :id, :fullname, checked: #selected_contact_ids
and then check boxes with items of id 1, 2 and 3 will be checked. You will need to pass this array obviously from the controller somehow. E.g.
#selected_contact_ids = email_params.fetch(:contact_ids, [])

Rails controller saving from different table

I'm new to rails to bear with me.
This concerns two of my models: Product and Manufacturer.
When creating a new product the user can select which manufacturer the product belongs to from a drop down list. The problem is that I can't get this manufacturer to save.
I know I have to add some code to the controller and I've tried various things but to no avail.
Here's the view:
<h1>New Product</h1>
<%= form_for(#product) do |f| %>
<div>
<%= f.label :name, 'Name' %>
<%= f.text_field :name %>
</div>
<div>
<%= f.label :market_price, 'Market Price' %>
<%= f.text_field :market_price %>
</div>
<div>
<%= f.label :sell_price, 'Sell Price' %>
<%= f.text_field :market_price %>
</div>
<div>
<%= f.label :stock_level, 'Stock Level' %>
<%= f.text_field :stock_level %>
</div>
<div>
<%= f.label :manufacturer, 'Manufacturer' %>
<%= f.collection_select(:manufacturer, Manufacturer.all, :id, :name, prompt: true) %>
</div>
<div>
<%= f.label :location, 'Location' %>
<%= f.collection_select(:location, Product.all, :id, :location, prompt: true) %>
</div>
<br> </br>
<div>
<%= f.submit "Create Product" %>
</div>
And here's part of the controller:
def create
#product = Product.new(params[:product].permit(:name, :market_price, :sell_price, :stock_level, :location))
#product.save
flash[:notice] = 'Product Created'
redirect_to #product
end
end
After hours of trying several nesting methods, I still can't get this to work.
Surely it's very common to save fields from various models on one page???
You would usually nest your routes, so that products were within manufacturer:
resources :manufacturer do
resources :products
end
Then your form would be a form for an array:
form_for([#manufacturer, #product]) do |f|
f.hidden_field :manufacturer_id, value: #manufacturer.id
This allows you to pass in the ID of both the manufacturer and the product.
Now in your controller you can use something like the following, provided the associations are set up, such as product belongs_to :manufacturer and manufacturer has_many :products
#manufacturer = find(params[:manufacturer_id])
#product = #manufacturer.products.create()
In your form, you need to have a field for manufacturer_id, not manufacturer. You would change f.collection_select(:manufacturer to be f.collection_select(:manufacturer_id.
Then, in your controller, you need to add manufacturer_id to the list of parameters you are permitting in your permit method call. So it would be Product.new(params[:product].permit(:name, :market_price, :sell_price, :stock_level, :location, :manufacturer_id)).

undefined method `[]' for nil:NilClass error in rails

I have 2 conotrollers and 3 models:
Models:
problem.rb
class Problem < ActiveRecord::Base
has_many :problemtags
has_many :tags, :through => :problemtags
end
tag.rb
class Tag < ActiveRecord::Base
validate :name, :presence => true
has_many :problemtags
has_many :problems, :through => :problemtags
end
problemtag.rb
class Problemtag < ActiveRecord::Base
belongs_to :problem
belongs_to :tag
end
problems_controller.rb
class ProblemsController < ApplicationController
def new
#all_tags = Tag.all
#new_problem = #problem.problemtags.build
end
def create
params[:tags][:id].each do |tag|
if !tag.empty?
#problem.problemtags.build(:tag_id => tag)
end
end
end
def problem_params
params.require(:problem).permit(:reporter_id, :status, :date_time, :trace_code)
end
tags_controller.rb
//tags_controller is generate with scaffold
And I have below code in problems view:
new.html.erb
<%= fields_for(#new_problem) do |f| %>
<div class="field">
<%= f.label "All Tags" %><br>
<%= collection_select(:tags, :id, #all_tags, :id, {}, {:multiple => true}) %>
</div>
<% end %>
when I run the project, the problem's view is show, but when I complete the textfields and select tags and then click on submit button, I get below error:
NoMethodError in ProblemsController#create
undefined method `[]' for nil:NilClass
Extracted source (around line #22):
#problem = #reporter.problems.build(problem_params)
params[:tags][:id].each do |tag|
if !tag.empty?
#problem.problemtags.build(:tag_id => tag)
end
I do not understand the problem. any one can describe the problem to me?
As stated by your answers, your issue is that you're not sending the right data to your controller (and consequently params[:tags] will be blank):
Form
You're firstly missing the form_builder object in your collection_select (so your tags will likely not be sent inside the correct params hash). Although this may be by design, you need to ensure you're passing the data properly:
<%= fields_for(#new_problem) do |f| %>
<div class="field">
<%= f.label "All Tags" %><br>
<%= f.collection_select(:tags, :id, #all_tags, :id, {}, {:multiple => true}) %>
</div>
<% end %>
Params
Secondly, we cannot see your form or params hash. This is vital, as your form needs to look like this:
<%= form_for #variable do |f| %>
<%= f.text_field :value_1 %>
<%= f.text_field :value_2 %>
<% end %>
This creates a params hash like this:
params { "variable" => { "name" => "Acme", "phone" => "12345", "address" => { "postcode" => "12345", "city" => "Carrot City" }}}
This will be the core reason why your controller will return the [] for nil:NilClass error - you'll be referencing params which don't exist. You'll need to call params[:variable][:tags] as an example
If you post back your params hash, it will be a big help
You could try using validate :tag_id, :presence => true to check for presence of the needed params.
I found 2 problems in my code:
in new.index.html(in problem view), the submit button is in the form_for and I write the field_for outside the form_for and when I click on submit button, the params hash of tags didn't create.
In collection_select, I forgot to add the name parameter of tag.
Correct new.html.erb code:
<%= form_for #problem do |f| %>
status: <%= f.text_field :status %><br/>
datetime: <%= f.datetime_select :date_time %><br/>
trace code: <%= f.text_field :trace_code %><br/>
<%= fields_for(#new_problem) do |f| %>
<div class="field">
<%= f.label "All Tags" %><br>
<%= collection_select(:tags, :id, #all_tags, :id,:name, {}, {:multiple => true}) %>
</div>
<% end %>
<%= f.submit %>
<% end %>
Thanks for all of the answers.

Rails 3 serialized form attribute

I have the following model:
class Deck < ActiveRecord::Base
has_many :cards
serialize :stats
attr_accessible :name, :description, :stats
end
In this, stats should be an array of strings. I want to be able to add an arbitrary number of stats to the row (using javascript to add additional "stat" input boxes, but that is outside the scope if the question.)
My question is how do I reflect this structure in the view? If I was building the form manually then it would look like:
<input type="text" name="deck[stats][]">
My view currently looks like:
<%= f.fields_for :stats, #deck.stats do |p| %>
<%= p.label :p, "Stats: " %>
<%= p.text_field :p %>
<% end %>
But this outputs:
<input type="text" name="deck[stats][p]">
I also want a counter so I can display the label as "Stat 1:", "Stat 2:", etc.
Any help is appreciated.
Posting the solution I went for to aid future readers.
#Controller
def new
#deck = Deck.new
#deck.stats = ["", ""] #include for number of times you wish to show the field.
end
#View
<%#deck.stats.each_with_index do |s,i| %>
<p>
Stat <%=i+1%>: <%=text_field "stat", i, :name => "deck[stats][]", :value => s %>
</p>
<%end%>
By defining :p you are making it think you are looking for a method on stats called p, ie stats.p
<%= f.fields_for :stats, #deck.stats do |p| %>
<%= p.label :p, "Stats: " %>
<%= p.text_field :p %>
<% end %>
Rather just try <%= p.text_field %> drop the :p
I don't know if there's a clean way of doing it, but this should work:
<% #deck.stats.each do |value|
<%= f.fields_for :stats do |fields| %>
<%= fields.text_field "", :value => value %>
<% end %>
<% end %>
= simple_form_for [:stats, #deck] do |f|
- 1.upto(4) do |i|
= f.input_field :stats, multiple: true, label: "Stat #{i}"
= f.submit

Resources