Select some fileds from object in mongoid - ruby-on-rails

Hi I need to select only particular fields from object.
something like this using mongoid
User.select(:name, :email).all
please help me.
I don’t know why only is not working for me if i use as_json on it.
User.only(:name, :email).all.as_json
is throwing attributes missing error.

The only method works for me. Are you certain that mongo is returning a value for the other parameters? The attributes should still exist for those extra parameters, but they should be assigned to nil instead.
1.9.3-p194 :011 > Retailer.only(:description).all.first
=> #<Retailer _id: 1, description: "WALMART", aliases: nil>
1.9.3-p194 :012 > Retailer.all.first
=> #<Retailer _id: 1, description: "WALMART", aliases: ["WALMART.COM", "WAL-MART"]>

Related

Calling the .name method does not return the object's name

I am trying to get the category object to return the name "Comedy", but is returning "Category" instead when I call the name method. Not sure where to look to solve this issue so I would appreciate if someone can point me in the right direction.
pry response from command link:
[17] pry(#<QueueItem>)> category
=> [#<Category id: 1, name: "Comedy", created_at: "2014-03-17 19:21:34", updated_at: "2014-03-17 19:21:34">]
[18] pry(#<QueueItem>)> category.name
=> "Category"
Thanks!
From the above code and output, it seems like, category variable is storing an array of category ActiveRecord Objects. So we need to use the object by the following code.
category.first.name
Just to clarify, if we try on console category.class we should get:
> category.class
# ActiveRecord::Relation::ActiveRecord_Relation_Category
That's why it didn't throw Error, undefined method name for Array, simply because it is not an Array, and Rails Active Record Relations do have a name method
Actually, i never used pry but default rails console would have dumped the class name before the data:
> category
#<ActiveRecord::Relation [#<Category id: 1, ....>, #<Category id:2 ...>, .. etc]
Which is really useful.

Why is the "where" query in rails returning a different object?

I'm testing chats between users in my app. I'm using RSpec and FactoryGirl
The test that's not passing:
it "creates a chat if one does not exist" do
bob = create(:user, username: "bob")
dan = create(:user, username: "dan")
new_chat = Chat.create(user_id: #dan.id, chatted_user_id: bob.id)
expect(Chat.where("chatted_user_id = ?", bob.id).first).to equal(new_chat)
end
The failure message says:
Failure/Error: expect(Chat.where("chatted_user_id = ?", bob.id).first).to equal(new_chat)
expected #<Chat:70120833243920> => #<Chat id: 2, user_id: 2, chatted_user_id: 3>
got #<Chat:70120833276240> => #<Chat id: 2, user_id: 2, chatted_user_id: 3>
Compared using equal?, which compares object identity,
but expected and actual are not the same object. Use
`expect(actual).to eq(expected)` if you don't care about
object identity in this example.
Why is my query returning a different object id?
equal checks object identity. The objects you are testing are two objects (instances) referencing the same record, but they are actually different objects from a Ruby virtual machine point of view.
You should use
expect(Chat.where("chatted_user_id = ?", bob.id).first).to eq(new_chat)
To better understand the problem, look at the following example
2.0.0-p353 :001 > "foo".object_id
=> 70117320944040
2.0.0-p353 :002 > "foo".object_id
=> 70117320962820
Here I'm creating two identical strings. They are identical, but not equal because they are actually two different objects.
2.0.0-p353 :008 > "foo" == "foo"
=> true
2.0.0-p353 :009 > "foo".equal? "foo"
=> false
That's the same issue affecting your test. equal checks if two objects are actually the same at the object_id level. But what you really want to know is if they are the same record.

Rails Model.where how do I get ID?

I have the following where statement:
<% location = Location.where('locname' == client.locname) %>
How do I get the .id of the location record that it found?
This didn't work:
<% location = Location.where('locname' == client.locname).id %>
Thanks for the help!
<% location = Location.where("locname = ?", client.locname).first.id %>
The reason is that where will return an ActiveRecord::Relation, thus you can either loop through the elements or just grab the first one as I did above.
You may also use the find method provided by ActiveRecord like:
<% location = Location.find(:first, :conditions => ["locname = ?", client.locname]).id %>
be also aware that you need to paramterize your query properly to eliminate all possibilities of SQL injection.
The reason why your first code sample you provided doesn't allow you to obtain the id, is it isn't an instance of the Location class. Using some code from my own project:
1.9.2p290 :001 > ch = Character.where(name: 'Catharz')
Character Load (2.9ms) SELECT "characters".* FROM "characters" WHERE "characters"."name" = 'Catharz'
=> [#<Character id: 2, name: "Catharz", player_id: 2, archetype_id: 4, created_at: "2012-03-29 07:10:31", updated_at: "2012-11-26 05:36:11", char_type: "m", instances_count: 348, raids_count: 148, armour_rate: 5.1, jewellery_rate: 5.29, weapon_rate: 5.48>]
1.9.2p290 :002 > ch.class
=> ActiveRecord::Relation
This is because returns an instance of the ActiveRecord:Relation class which mimics your class. You can see this by calling #klass on the returned value.
1.9.2p290 :002 > ch.klass
=> Character(id: integer, name: string, player_id: integer, archetype_id: integer, created_at: datetime, updated_at: datetime, char_type: string, instances_count: integer, raids_count: integer, armour_rate: float, jewellery_rate: float, weapon_rate: float)
But if you try and get an id, you'll get the following exception:
1.9.2p290 :004 > ch.id
NoMethodError: undefined method `id' for #<ActiveRecord::Relation:0xce58344>
The ActiveRecord::Relation class allows you to chain together scopes, without executing the SQL until you need it to be executed. This is why Luis' answer above will work. Calling #first on the ActiveRecord::Relation will force the query to be executed.
As a pointer on design, you should probably be assigning your location as #location in your controller then using the instance variable in your view.

Rails build method modifies object

Let's say I have this simple method in my helper that helps me to retrieve a client:
def current_client
#current_client ||= Client.where(:name => 'my_client_name').first
end
Now calling current_client returns this:
#<Client _id: 5062f7b851dbb2394a00000a, _type: nil, name: "my_client_name">
Perfect. The client has a few associated users, let's look at the last one:
> current_client.user.last
#<User _id: 5062f7f251dbb2394a00000e, _type: nil, name: "user_name">
Later in a new method I call this:
#new_user = current_client.user.build
And now, to my surprise, calling current_client.user.last returns
#<User _id: 50635e8751dbb2127c000001, _type: nil, name: nil>
but users count doesn't change. In other words - it doesn't add the new user but one user is missing... Why is this? How can I repair it?
current_client.users.count makes a round trip to the database to figure out how many user records are associated. Since the new user hasn't been saved yet (it's only been built) the database doesn't know about it.
current_client.users.length will give you the count using Ruby.
current_client.users.count # => 2
current_client.users.length # => 2
current_client.users.build
current_client.users.count # => 2
current_client.users.length # => 3

rails Model.create(:attr=>"value") returns model with uninitialized fields

This is really stumping me. The process works fine if I go about it with #new and then #save, but #create returns a model instance with all the fields set to nil.
e.g:
Unexpected behavior:
ruby-1.9.2-p0 > EmailDefault.create(:description=>"hi")
=> #<EmailDefault id: nil, description: nil, created_at: nil, updated_at: nil>
Expected behaviour:
ruby-1.9.2-p0 > e = EmailDefault.new
=> #<EmailDefault id: nil, description: nil, created_at: nil, updated_at: nil>
ruby-1.9.2-p0 > e.description = "hi"
=> "hi"
ruby-1.9.2-p0 > e.save
=> true
ruby-1.9.2-p0 > EmailDefault.last
=> #<EmailDefault id: 4, description: "hi", created_at: "2011-02-27 22:25:33", updated_at: "2011-02-27 22:25:33">
What am I doing wrong?
--update--
Turns out I was mis-using attr_accessor. I wanted to add some non-database attributes, so I did it with:
attr_accessible :example_to, :cc_comments
which is wrong, and caused the situation #Heikki mentioned. What I need to do is:
attr_accessor :example_to, :cc_comments
You need to white list those properties with attr_accessible to enable mass-assignment.
http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html#method-i-attr_accessible
--edit
By default all attributes are available for mass-assignment. If attr_accessible is used then mass-assignment will work only for those attributes. Attr_protected works the opposite way ie. those attributes will be protected from mass-assignment. Only one should be used at a time. I prefer the white listing with attr_accessible.

Resources