1

I'm running a search using the Ransack gem.

Controller code (for ItemsController)

@q = Item.search(params[:q])
@search_results = @q.result

After running the search, @search_results contains multiple Items (Item 1, Item 2, Item 3, …). Where each Item is a hash:

Item = { "id" => "12", "name" => "shovel", "user_id" => "2", "type" => "A" }

In this case, for each Item hash, I want to add an additional key-value pair that translates the user_id into the name that is associated with that instance of the User model (i.e., User has_many :Items and Item belongs_to :Users)

I tried in the same controller code section

@search_results.each do |item|
    item[:user_name] = User.find_by_id(item.user_id).name
end

But I get an error that I can't write to item. I suspect Ransack has something to do with it though, because if I just print @search_results, instead of getting the actual Item data, I get #<ActiveRecord::Relation::ActiveRecord_Relation_Item:0x000001025e6c78>

Help greatly appreciated!

Btw, in case there's even an easier way, the reason I want to add another key/value pair with the user_name is because the ultimate output is a JSON that is being picked up by another part of the codebase, and we don't want to run two separate database queries.

james
  • 3,989
  • 8
  • 47
  • 102
  • Well as for appending to hashes use: `item[:user_name] << User.find_by_id(item.user_id).name` in the each do block, or `item.merge!(user_name: User.find_by_id(item.user_id).name )` – Babar May 04 '14 at 08:06

1 Answers1

2

Firstly, you're receiving a ruby object back, which I take means you can create a set of attributes for in the model. Why don't you try using a getter in your item model to set for you:

#app/models/item.rb
Class Item < ActiveRecord::Base
    belongs_to :user #-> needs to be singular
    attr_accessor :user_name

    def user_name
       self.user.name
    end
end

This means that instead of having to append a user_name attribute from your controller, every Item object will automatically have the user_name attribute anyway

A refactor of this would also be to use the delegate method inside your Item model:

Class Item < ActiveRecord::Base
    belongs_to :user
    delegate :name, to: :user, prefix: true #-> allows you to call @item.user_name
end
Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • That's fine in the sense that I can get the data, but if I call the Item as an object, `user_name` is still missing from the hash (true in both approaches). – james May 04 '14 at 17:11