I am pretty new in rails and honestly, I am struggling with queries even after multiple researchs.
Here is my simple schema:
So basically, a question has many options, an option belongs to a question and has many answer, and an answer belongs to an option and has many users.
I don't think it s necessary to post the models code since it is just like i mentioned above.
What i would like to do is given a question option, see if a particular user already checked it (so look in the answer table if there is a row matching a given id_option, user_id and user_type). So in my haml loop, when displaying the different question option, i'm calling a method of my question_option model just like this :
- question.question_option.all.each do |option|
#{option.title}
.check
- if option.selected_by(current_actor)
= check_box_tag(option.id, "checked",true, class: 'styled-checkbox')
- else
= check_box_tag(option.id, "checked",false, class: 'styled-checkbox')
and the method called :
def selected_by(answerer)
answer_match =
::Vacancies::QuestionOption
.joins(:answers)
.where(answerer_id: answerer.id, answerer_type:answerer.type )
response = answer_match.find(self.id)
return response
end
This method is located in my QuestionOption model and leads to no errors but it s not working ever.
Can you help me transform this query to make it work with ActiveRecord ? Thanks
Try the below code. It checks if there are any answers by the user passed in the params on the question. I think this is what you intended to do as well-
def selected_by(answerer)
answers =
Answer.where(answerer_id: answerer.id, answerer_type:answerer.type, id_option: self.id)
answers.exists?
end
Related
Suppose I have a Rails model: class Project < ActiveRecord::Base
In the Rails console:
> Project.all
=> #<ActiveRecord::Relation []>
That seems reasonable. However,
> Project.all.class
=> Project::ActiveRecord_Relation
What is Project::ActiveRecord_Relation? Specifically,
How did it get "added" (namespaced into) to my model class?
How does it respond to is_a? correctly? Project.all.is_a?(ActiveRecord::Relation) returns true (which is expected), but is Project::ActiveRecord_Relation actually an instance of ActiveRecord::Relation, or is it something else?
Why do this? Why doesn't Project.all return an ActiveRecord::Relation, rather than Project::ActiveRecord_Relation?
(This is in the context of Rails 5.1, in case it's changed in older or newer versions.)
(I'm open to title edits if someone else can come up with a better title for this question)
Check this line of code from ActiveRecord.
https://github.com/rails/rails/blob/f40860800c231ecd1daef6cf6b5a8a8eda76478d/activerecord/lib/active_record/relation/delegation.rb#L23
mangled_name = klass.name.gsub("::", "_")
So, for your questions:
it get's added on activerecord's base when it extendes the delegation module https://github.com/rails/rails/blob/f40860800c231ecd1daef6cf6b5a8a8eda76478d/activerecord/lib/active_record/base.rb#L290
it's actually the same class, just something like an alias (not actually an alias, it's a constant with the class as value)
the class is actually an ActiveRecord::Relation, it's just that the name was changed
There are actually two questions you are asking:
How does it work?
Why is it like that? (What for?)
#arieljuod has already given you some explanations and a link.
However the second question is still unanswered.
There is another similar question exists which I hope will help you find all the answers:
How can an ActiveRecord::Relation object call class methods
It looks like the two questions (by the link and yours one) answer each other )
Take a look at #nikita-shilnikov's answer. Good luck in your investigation!
In my rails app I have defined in the Kid model a calculation based on the fields from the Kids DB. the method is as follows:
def flip_date
self.dob.advance(months: 10)
end
I want to use this in my controller as I have a method where I am defining something as follows:
new_kids = Kid.where(discharge_date: nil).where('flip_date > ?', Date.current.advance(year: 1).beginning_of_year)
However I keep getting the following error:
SQLite3::SQLException: no such column: flip_date: SELECT "kids".* FROM "kids" WHERE "kids"."discharge_date" IS NULL AND (flip_date < '2017-01-01')
Any ideas on how can I make this work? All help is appreciated!
If you really want to use model methods take a look at http://apidock.com/rails/v4.0.2/ActiveRecord/QueryMethods/select
For your case:
new_kids = Kid.where(discharge_date: nil).select{|k| k.flip_date > Date.current.advance(year: 1).beginning_of_year}
But select method takes every object in memory before returning final result. Hence I will advise to use normal where clause and instead of flip_date take dob (which is a column in database) in consideration.
Like this
new_kids = Kid.where(discharge_date: nil).where('dob > ?', <date criteria>)
The select method (http://apidock.com/rails/v4.0.2/ActiveRecord/QueryMethods/select) works great if you are okay with the return being an Array.
I am still looking for a way to do this with an ActiveRecord_Relation return.
If others know how to do this, it would be much appreciated if you can share.
This example doesn't respond to your specific code, but to the extent it helps someone else with a similar question, here's a very simple example of how .select can be really handy:
#expired_memberships = User.select{|u| u.membership_expired_yesterday?}
In that example you've looped through all your Users and filtered them based on a custom method you defined on the User model (membership_expired_yesterday?). Now you can easily do stuff with that collection like this example in a mailer:
#expirations.each do |user|
MembershipExpirationMailer.with(user: user).first_reminder.deliver_now
end
Scenario: I have a quiz type setup where Questions have many Answers and also have a Response provided by the user (omitted). A response has a selected attribute to indicate the user's choice and a correct? method that compares selected with the correct_answer.
Code: is here in this GitHub repo, along with seed data. Quick links to:
Question.rb
Answer.rb
Response.rb
Problem: I want to return all responses for a question that are correct however, unsaved records are not included.
I've tried a couple of different ways, as you'll see in the code including scope, question.correct_responses and also inverse_of (which I've read is supposed to be automatic now) - but to no avail.
Basically, I'm expecting following code to return 1, not 0.
q=Question.first
r=q.responses.build
r.selected = q.correct_answer
q.responses.correct.size # => 0??! wtf man!?
Your assistance is greatly appreciated.
When you use a scope you're going to the database.
Since you aren't saving the response, you don't want to go to the database. Instead, you should use something like the line below, which will select all of the question's "correct" responses and then count them.
q.responses.select { |r| r.correct? }.size
EDIT: or the short syntax for select:
q.responses.select(&:correct?).size
I am totally new to ActiveRecord so this maybe a dumb question:
I had written my method like this:
sample_organizations = [ '37 Signals', 'Fog Creek']
sample_organizations.each { |item|
Organization.first_or_create(
name: item,
time_zone: 'Central'
)
}
and it didn't work, I was hoping it will iterate through my array of organiations and will insert them all in the DB, but it just inserted one first row.
Then someone suggested to change it like this and THIS one worked, But I was wondering if someone can explain what was wrong in the first method so I can learn what was I doing/assuming wrong.
so this one worked:
sample_organizations = [ '37 Signals', 'Fog Creek']
sample_organizations.each { |item|
Organization.where(name: item).where(time_zone: 'Central').first_or_create
}
Actually, there are two methods: find_or_create_by, add one column and give a set of attributes.
So, for example you can write:
find_or_create_by_name('Willy', time_zone: 'UTC')
The second is first_or_create, and that works as you were suggested (your second solution) (see the documentation as well).
There was a suggestion to introduce the find_or_create method, which accepts a hash, but that resulted in the first_or_create. (see discussion here).
Note that both are also explained well in the relevant rails guide.
[UPDATE 2014-06-30] Note that currently the notation has been changed, we should now write
Organization.find_or_create_by(name: '37 signals') do |organisation|
organisation.time_zone = 'Central'
end
which will try to find the organisation by name, and if not found use the block to create the organisation. Note: the block is only executed if the organisation did not exist!
It should be like below:
sample_organizations.each { |item|
Organization.find_or_create_by_name(item, time_zone: 'Central')
}
How can I get duplicate posts in my view?
I want to be able to do something like this:
#post = post.find(1,2,1)
to return post 1 , post 2 and then post 1 (again).
realize this is a dumb question but I can't find any documentation.
Although I'm not sure about the use case you can do something like:
#posts = Post.find(1,2) << Post.find(1)
of you can define this in your Post model:
def find_with_array(*args)
posts = []
for arg in args
posts << Post.find(arg)
end
posts
end
Obviously the above is inefficient as you are making many SQL calls. If you want it efficient then you can write a code that makes one sql call (but will not return duplicates) and then iterate through the array and rearrange (with copying for duplicates) such as (not fully tested):
def find_with_array(*args)
posts_with_no_duplicates = Post.find(args)
posts_with_duplicates = []
for arg in args
for post in posts_with_no_duplicates
if arg == post.id
posts_with_duplicates << post
end
end
end
end
This one should be better as you are only making one call to DB (normally slowest part) however it's O(N^2) There might be a way to make it O(N) if need be. However It's great improvement from the previous option
Without knowing more detail, here's what I would advise. Take a look at this post regarding checkbox arrays: http://www.skuunk.com/2008/05/checkbox-arrays-in-rails.html
Each checkbox drops a value into a particular params key. This will solve the problem of getting an array with a list of values. Let me know in the comments if this doesn't resolve your particular issue.