Gregory_ynwa
Gregory_ynwa

Reputation: 168

How to get an attribute from a Rails association

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

Answers (3)

Vishal Jain
Vishal Jain

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

sadaf2605
sadaf2605

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

Lanny Bose
Lanny Bose

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

Related Questions