ive weird behaviour in my model code,
but iam not sure if this is my problem or is it some weird issue with ruby on rails.
ive a associated
has_many :chat_user #linked to ChatUser
and ive defined
Class A
def guest
chat_user #returning chat_user from has_many
end
end
ive 2 records of ChatUser which is linked to this model class
when i called object of Chat A .chat_user -> count and each return 2 records
when i called object of .guest -> count return 2, but each loop only once!
what could be the issue?
thank you
using rails 4.0.0 with puma server
I found the issue, I've actually returned a custom where query with limit 1 applied to chat_user, hidden in a function.
Related
I am working on an app that allows Members to take a survey (Member has a one to many relationship with Response). Response holds the member_id, question_id, and their answer.
The survey is submitted all or nothing, so if there are any records in the Response table for that Member they have completed the survey.
My question is, how do I re-write the query below so that it actually works? In SQL this would be a prime candidate for the EXISTS keyword.
def surveys_completed
members.where(responses: !nil ).count
end
You can use includes and then test if the related response(s) exists like this:
def surveys_completed
members.includes(:responses).where('responses.id IS NOT NULL')
end
Here is an alternative, with joins:
def surveys_completed
members.joins(:responses)
end
The solution using Rails 4:
def surveys_completed
members.includes(:responses).where.not(responses: { id: nil })
end
Alternative solution using activerecord_where_assoc:
This gem does exactly what is asked here: use EXISTS to to do a condition.
It works with Rails 4.1 to the most recent.
members.where_assoc_exists(:responses)
It can also do much more!
Similar questions:
How to query a model based on attribute of another model which belongs to the first model?
association named not found perhaps misspelled issue in rails association
Rails 3, has_one / has_many with lambda condition
Rails 4 scope to find parents with no children
Join multiple tables with active records
You can use SQL EXISTS keyword in elegant Rails-ish manner using Where Exists gem:
members.where_exists(:responses).count
Of course you can use raw SQL as well:
members.where("EXISTS" \
"(SELECT 1 FROM responses WHERE responses.member_id = members.id)").
count
You can also use a subquery:
members.where(id: Response.select(:member_id))
In comparison to something with includes it will not load the associated models (which is a performance benefit if you do not need them).
If you are on Rails 5 and above you should use left_joins. Otherwise a manual "LEFT OUTER JOINS" will also work. This is more performant than using includes mentioned in https://stackoverflow.com/a/18234998/3788753. includes will attempt to load the related objects into memory, whereas left_joins will build a "LEFT OUTER JOINS" query.
def surveys_completed
members.left_joins(:responses).where.not(responses: { id: nil })
end
Even if there are no related records (like the query above where you are finding by nil) includes still uses more memory. In my testing I found includes uses ~33x more memory on Rails 5.2.1. On Rails 4.2.x it was ~44x more memory compared to doing the joins manually.
See this gist for the test:
https://gist.github.com/johnathanludwig/96fc33fc135ee558e0f09fb23a8cf3f1
where.missing (Rails 6.1+)
Rails 6.1 introduces a new way to check for the absence of an association - where.missing.
Please, have a look at the following code snippet:
# Before:
Post.left_joins(:author).where(authors: { id: nil })
# After:
Post.where.missing(:author)
And this is an example of SQL query that is used under the hood:
Post.where.missing(:author)
# SELECT "posts".* FROM "posts"
# LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
# WHERE "authors"."id" IS NULL
As a result, your particular case can be rewritten as follows:
def surveys_completed
members.where.missing(:response).count
end
Thanks.
Sources:
where.missing official docs.
Pull request.
Article from the Saeloun blog.
Notes:
where.associated - a counterpart for checking for the presence of an association is also available starting from Rails 7.
See offical docs and this answer.
Was following the Depot application from Agile Web Development with Rails.
There was a method I got confused. I thought I understood it until I tried it in irb. So here's the method:
def add_product(product_id)
current_item = line_items.find_by_product_id(product_id)
if current_item
current_item.quantity += 1
else
current_item = line_items.build(product_id: product_id)
end
current_item
end
From what I understood, It's just a method that will first find a record in LineItems with a product ID of an give input (let's say it's 10). Then it will store it in current_item variable. The condition says 'If the product id was found, add 1 to quantity else create a new instance of that record with the product id equals to 10'
Here's the snapshot of my rails console
As you can see, product id of 10 in LineItem is not found. But on my condition, it goes against everything that I believe until now. Could someone shed a light on this?
Looks like line is an empty collection (ActiveRecord::Relation to be exact) and so it's something in Ruby and not nil. That's why it's returning true when you're calling if line and executing puts 'I'm true and happy'.The reason it's an ActiveRecord::Relation is because you're using the where query.
In the Depot application they're making the query by calling line_items.find_by_product_id(product_id) which is different. It finds the first record matching the condition.
Check out the Rails guides here for more info - http://guides.rubyonrails.org/active_record_querying.html (section 15)
PS Looks like that type of query is deprecated in Rails 4 so not sure what version of Agile Web Development with Rails you're looking at.
I recently upgraded an old Rails 2.3 app (Ruby 1.8.7) to Rails 3.2 / Ruby 1.9.3. When using ActiveRecord serialize and trying to access a serialized attribute, i get:
ActiveRecord::AttributeMethods::Serialization::Attribute returned.
.unserialize then returns the actual value.
The real strange thing is, that there a some models which have a normal behavior.
Can someone help me?
I now figured out when this problem happens, but i still dont know why:
This works:
User < ActiveRecord::Base
serialize :options, Hash
end
Options return {}
If i call the model itself before serialize, like that:
User < ActiveRecord::Base
USER_LIST = User.all.map {|u| [u.name, u.id]}
serialize :options, Hash
end
i get ActiveRecord::AttributeMethods::Serialization::Attribute
Anybody got an idea?
Try using unserialized_value rather than unserialize, so it doesn't matter whether or not it has already been unserialized. For reference, view the source for the unserialized_value method here http://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/Attribute.html
Simple example might be a Post, that has three states, DRAFT, PUBLISHED and DELETED.
The way I do this right now is something like:
class Post < ActiveRecord::Base
DRAFT = 0
PUBLISHED = 1
DELETED = 2
end
The problem that arises is that when I'm running my tests using spork, I have to reload the model manualy, with something like
Spork.each_run do
Dir["#{Rails.root}/app/models/**/*.rb"].each { |model| load model }
end
Which in result gives me loads of warnings like
warning: already initialized constant DRAFT
warning: already initialized constant PUBLISHED
warning: already initialized constant DELETED
Everything works just fine, but I don't think this is the best way to do this. Is there a better way to do this? I know there are gems like acts_as_state_machine, but I'd like to know a non-gem solution if there is a simple one.
I trying to get mongoid to save associations, but I can only get one side to work. If I have the following test.
test "should add a user as a follower when a user follows the group" do
#cali_group.followers = []
#user1.followed_groups << #cali_group
assert_equal 1, #user1.followed_groups.count
assert_equal 1, #cali_group.followers.count
end
Which is failing, because #cali_group.followers is []. I've been working with this for awhile, tried #cali_group.reload. But it looks like the only way to do this in my code is to work both ends of the join, i.e. #cali_group.followers << #user1. I can do that in my code if I have to.
The models for polco_group and user are here: https://gist.github.com/1195048
Full test code is here: https://gist.github.com/1195052
It can be that:
https://github.com/mongoid/mongoid/issues/1204
Very late to the show. Using Mongoid 4.0.2 here. The issue is troubling me as well.
The link by #sandrew is no longer valid. A similar issue was reported here: http://github.com/mongodb/mongoid/pull/3604
The workaround that I found was:
#cali_group.followers = []
#cali_group.follower_ids # Adding this line somehow does something to the cache
#user1.followed_groups << #cali_group
Found this workaround by adding a before_save in the Group class and observing self.changes. Without this line, the follower_ids member changes from nil to []. However after adding the line, the correct ID of the user is received and set. Hope that helps any future reader.