I have a model, Report and I'd like to create a method users such that I can call #reports.users and get a list of all users for all reports in the array. Where do I write the function definition?
seems like you need to add static method in your reports model. Its better if you name your method some thing other than 'users' because if you have association like this
has_many :users
it will cause couple of errors or may be anonymous behaviors.
def self.get_all_users
all_users = collect{|report| report.users}
all_users.flatten!
end
now
#reports.get_all_users
will return all users
I think you need relationship to call that function
In Your reports model,
add these
belongs_to :user
In Your user model
add
has_many :reports
Make sure your report model has user_id field.
Then you can call
#report.users from your report controller.
like this in your report controller index method
#reports = Report.users
Related
I am adding a feature to an old app that was not made by me, this along with being relatively new to RoR is leading to some confusion for me.
I have models called reponse, activity_point, and report
response has two parents, it belongs_to activity_point and report.
I am trying to access activity_points for a do block like so:
report.responses.activity_points.activity.each do |a|
Obviously that isn't working. I am getting the error message:
undefined method `activity_points' for []:ActiveRecord::Relation
Thanks to anyone who can help me with this little problem.
Or you can add something like this to your Report model
has_many :responses
has_many :activity_points, :through => :responses
has_many :activities, :through => :activity_points
then you can do this
report.activities.each do |a|
Another way to do this kind of thing, add a method to Report and joins from the other side (to get activity objects)
def activities
Activity.joins(:activity_points => :responses).where('responses.report_id = ?', id)
end
The point of doing all this, you don't want to create Ruby objects if you don't need to. Nested loops are also a potential problem with unique items and sorting.
Each response have several activity_points so you should iterate through responses. Also each activity_point has several activities, so:
report.responses.each do |r|
r.activity_points.each do |ap|
ap.activity.each do |a|
# Do your thing
end
end
end
First, when you write report.responses, this will return an ActiveRecord array. Since activity_points is an undefined method for arrays, you can't call it. So to call this method there is two conditions:
You have to tell your app which element of the array will call the method. For instance, report.responses.first.activity_points or report.responses.second.activity_points ...
Response model has to have a has_many: activity_points to call this method.
You could still also use a loop, but that will take multiple DB calls. Therefore, my solution involves direct database call for efficiency.
Activity.includes(activity_point: {responses: :report}).where(reports: {id: report.id}).each do |a|
#...
#...
end
I'm working on implementing a tagging system and I'm having problem querying for tagged objects with a scope.
For example, I would like to find all the user's items with a certain tag. With a class method I can currently find all the objects:
def self.tagged_with(name)
Tag.find_by_name(name).items
end
However, this has a problem. If I were to do something like: current_user.items.tagged_with(name) won't this existing method return ALL the items and not just items owned by the current_user? I suppose this is a simply querying issue but I can't figure out how to change a class method into something called on a collection. I have tried going the opposite way, to get a the collection through the tags, something like... tag.items.where(:user_id => current_user.id) but in this case, it's a many-to-many relationship and I haven't been able to get on thumb on this either.
What's the proper way to restrict a query like this?
Create an association on your User class that points to your Tag class.
class User < ActiveRecord::Base
has_many :tags
end
Then you can do:
current_user.tags.where(...)
If you don't already have an association in place, you'll need to create a migration to have the tags table reference your users table with a foreign key.
I think this will help you:
class Account < ActiveRecord::Base
has_many :people do
def find_or_create_by_name(name)
first_name, last_name = name.split(" ", 2)
find_or_create_by_first_name_and_last_name(first_name, last_name)
end
end
end
person = Account.first.people.find_or_create_by_name("David Heinemeier Hansson")
person.first_name # => "David"
person.last_name # => "Heinemeier Hansson"
So, basically you can define your method tagged_with directly into the association!
This example is took from the documentations ActiveRecord::Associations
I have a Record model and in order to edit this model, you must be logged in as an instance of Admin. I would like to have a column called last_modified_by which points to the Admin who last modified the Record. In the database, I was thinking it would be good in the records table to add a column that holds the Admin's id; however, the only way I know how to do that is with an association. These two models are not associated with each other so an association doesn't make a lot of sense. Is there any other way I might be able to accomplish this task without resorting to associations? Any advice would be much appreciated!
Hmm, I think the association is a good tool here. You might want to try to hack it somehow but I think nothing you can conjure up will ever be as good as an association via a foreign_key(also so fast). But perhaps you would like to name your association and do something like:
class Record < ActiveRecord::Base
belongs_to :culprit, :class_name => 'Admin', :foreign_key => 'last_modified_by'
end
or give it some more senseful naming?
You could create an Active Record before_save callback. The callback would save the admin's id into the last_modified_column. This would make sure the admin id is saved/updated each time there is a change to the model.
For example, assuming admin is #admin:
class Record < ActiveRecord::Base
before_save :save_last_modified
def save_last_modified
self.last_modified_column = #admin.id
end
As for getting #admin, you could employ a method similar to this, and set #admin = Admin.current (like User.current in the link) somewhere in the Record model.
Hi for rails model association, i know i can do this:
For example a model class Page.
class Page < ActiveRecord::Base
has_many :parts
end
I can do this:
Page.first.parts.find_by_name('body')
Page.first.parts.class actually returns Array. How can it activate methods for Part model? I found the similar post on How do rails association methods work?
My question is that when i try to use memcache to cache the response for parts methods. Then when i call Page.first.parts.find_by_name('body'), it tells me that the Array doesn't have method find_by_name. How do i solve this problem? I need to have the cache as this is one heavily used methods.
class Page
def parts_with_cache
Rails.cache.fetch("parts_for_page_#{id}", {:expires_in => 1.minutes}) do
parts_without_cache
end
end
alias_method_chain :parts, :cache
end
Since you are getting back an array of Parts objects associated to the Page object unfiltered by part name, just do an Array select method on the result set.
body_parts = Page.first.parts.select{ |part| part.name == 'body' }
My models are like this: a discussion has_many posts (nested resource).
I want to add a starter_post_id column to the discussions table, and have it record the 'thread starter post id'. The discussion is created along with the post in the nested form, and that when the logic should be called, because other posts to that discussion will be replies not starter posts.
I am not sure what I need to do after the add_column db migration.
Do I need a belongs_to :post in my Discussion model?
What's the order of creation for these nested objects. e.g. parent's creation ends before child's starts? or will the parent constructor call the child constructor?
Which model should the starter post assignment logic go to? This is related to Q2 since both objects needs to be initiated, but preferably before the DB call.
I would use the created_at field from you post model to determine the starter_post of a discussion. No need for any columns.
Add something like this in your discussion model
def starter_post
self.posts.order("created_at ASC").first()
end
If you use this in you discussion.rb :
has_many :posts , :order => "created_at ASC"
you can then simply use :
def starter_post
self.posts.first()
end
I tried before_save and it won't work because at that point in time the discussion has no way to get hold of the starter post object. I was pointed out to use after_create instead.
def after_create
self.starter_post_id = self.posts.first.id
self.save!
end
This will cause one extra sql query, but it is better than doing it at the post model.
I used belongs_to so I can use discussion.start_post_id, but I guess it is optional.