Reputation: 168
I have a search form for searching in a specific model (Order). It works fine but i want to add in my search method a parameter from an association (transactions) which is nested like this: ["params"]["transaction_id"].With the code below, i get an error ActiveRecord::StatementInvalid in Orders#index
because i cannot express it in the right way. How can i fix this?
Model:
class Order < ActiveRecord::Base
has_many :transactions, :class_name => "OrderTransaction"
def self.search(params)
query = order('created_at DESC').joins(:transactions)
query = query.where('name LIKE ? OR email LIKE ? OR phone LIKE ? OR address1 LIKE ? OR state LIKE ? OR city LIKE ? OR **params.transaction_id** LIKE ?', "%#{params[:search]}%", "%#{params[:search]}%", "%#{params[:search]}%", "%#{params[:search]}%", "%#{params[:search]}%", "%#{params[:search]}%", "%#{params[:search]}%").order('created_at DESC') if params[:search].present?
query
end
end
Controller:
def index
@orders = Order.search(params)
end
View:
<%= form_tag orders_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search],id: "search_text", placeholder: " Search order" %>
<%= submit_tag "Search", :name => nil, class: "btn btn-success", id: "search_but_order" %>
</p>
<% end %>
Solution As @Lanny Bose suggest me, i create a new column for my Order model and i passed it the value of the serialized params to it. With this way i can now add it to my search method.
Upvotes: 0
Views: 477
Reputation: 1940
Hey you can try this way. if you column is serialize then you can used .to_yaml
converter before passing your searching string in this case you needs to create same hash as you are seriallize at time of store
we can create your string using yaml as:
yml_str = {:transcation_id => params[:search] }.to_yaml.gsub("-","").squish
you can used .squish
and gsub
method to remove unwanted ---
and \n
from string
simply your query from specific column as
Order.includes(:transactions).where("order_transactions.params like ?", "%#{yml_str}%")
Your method
def self.search(params)
query = order('created_at DESC').joins(:transactions)
query = query.where('name LIKE ? OR email LIKE ? OR phone LIKE ? OR address1 LIKE ? OR state LIKE ? OR city LIKE ? OR order_transactions.params LIKE ?', "%#{params[:search]}%", "%#{params[:search]}%", "%#{params[:search]}%", "%#{params[:search]}%", "%#{params[:search]}%", "%#{params[:search]}%", "%#{yml_str}%").order('created_at DESC') if params[:search].present?
query
end
Upvotes: 0
Reputation: 7540
Did you consider using scopes?
class Order < ActiveRecord::Base
scope :name, -> (name) { where("name like ?", "#{name}%")}
scope :email, -> (email) { where("email LIKE ?", "#{email}%")}
scope :phone, -> (phone) { where("phone LIKE ?", "#{phone}%")}
scope :address1, -> (address1) { where("address1 LIKE ?", "#{address1}%")}
scope :state, -> (state) { where("state LIKE ?", "#{name}%")}
scope :city, -> (city) { where("city LIKE ?", "#{city}%")}
scope :custom, -> (field, value) { where("#{field} LIKE ?", "#{value}%")}
end
Now we can solve the nested params problem the following way:
q=params[:search]
if q.present?
result = Order.name(q).or.email(q).or.phone(q).or.address1(q).or.state(q).or.city(q)
if params[:nested_query]
hash.each do |key, value|
result=result.or(key,value)
end
end
end
Upvotes: 0
Reputation: 1857
Before I begin, you have one logical error in Order.search
. You are setting query =
twice, which means you're just writing one query over the other. You want to chain them together.
As for how to construct the query, you're on the right track.
Model
def self.search(term)
if term
Order.order('created_at DESC').joins(:transactions).where("name LIKE :t OR email LIKE :t", t: term)
else
nil
end
end
Note the new syntax around :t
. Rails calls that Placeholder Conditions in the Rails Guide, and it will mean you don't have to copy your search variable over and over.
Also, I realized I only compared against name
and email
. I'll let you type in the rest of your fields. :)
Edit
Sorry, I neglected to spell this out. I would do the params processing in the controller, so I'm just passing a string to the model.
Controller
@orders = Order.search(params[:search])
...and that's definitely an issue of style over substance, I believe.
Upvotes: 1