Connecting database view with polymorphic model in rails - postgresql

I have the following setup which allows a user to have multiple projects and each project can have multiple tasks. A user can favourite multiple projects.
class User < ActiveRecord::Base
has_many :projects
has_many :tasks, :through => :projects
has_many :favourites
has_many :favourite_projects, :through => :favourites, :source => :favourable, :source_type => "Project"
has_many :favourite_tasks, :through => :favourite_projects, :source => :tasks
...
end
class Project < ActiveRecord::Base
belongs_to :user
has_many :tasks
has_many :favourites, :as => :favourable
...
end
class Task < ActiveRecord::Base
belongs_to :project
...
end
class Favourite < ActiveRecord::Base
belongs_to :user
belongs_to :favourable, :polymorphic => true
...
end
This setup allows #user.favourite_tasks to list all the tasks for the projects that they have favourited.
Taking the suggestion from here (http://pivotallabs.com/database-views-performance-rails/) I am trying to replace the multi-level table joins with a database view where possible instead.
The view SQL is:
SELECT tasks.id AS task_id, ..., projects.id AS project_id, ...
FROM tasks INNER JOIN projects ON projects.id = tasks.project_id
My new ProjectTask model is:
class ProjectTask < ActiveRecord::Base
self.primary_key = 'task_id'
end
I've updated my User model to include:
has_many :project_tasks
which works fine for #user.project_tasks.
However, I can't figure out what the has_many/has_one/belongs_to should be in the models for the favourites to work (connecting the favourites to the view rather than the projects table).
I'm aiming for has _many :favourite_project_tasks, :through => :favourites.... so that I can use #user.favourite_project_tasks in my controller and attach any ProjectTask model scopes to it if need be.
I think the fact that the ProjectTask model has task_id as the primary key is causing issue with rails linking the tables/view and because using :through overrides any use of :foreign_key and :primary_key (according to http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many).
Hopefully someone can advise what I should be doing because I've tried loads of combinations of changes with no joy.
Thanks

Issue seems to have been caused by the custom primary key.
By updating the User model with (I was already doing this when it was failing):
has_many :favourite_project_tasks, :through => :favourite_projects, :source => :project_tasks
to use the view and also changing the view to use:
SELECT tasks.id AS id, ...
rather than:
SELECT tasks.id AS task_id, ...
and changing the ProjectTask view model to use:
self.primary_key = :id
it now works.

Related

Save lab price on model to database rails

I have 3 models has_many, through relation : lab, medic_record, and lab_medic. In medic_record model, i have a method to calculate lab price and i have created a migration too for add column "lab_price:decimal" to medic_record
medic_record.rb
has_many :lab_medics, :dependent => :destroy
has_many :labs, :through => :lab_medics
before_save :finalize
def lab_price
Lab.where(:id => self.lab_ids).reduce(0) { |sum, x| sum += x[:price].to_f }
end
private
def finalize
self[:lab_price] = lab_price
end
lab.rb
has_many :lab_medics, :dependent => :destroy
has_many :medic_records, :through => :lab_medics
lab_medic.rb
belongs_to :lab
belongs_to :medic_record
My question is how to save a lab_price in medic_record model to database 'column :lab_price'? I have tried using 'before_save :finalize' method but the result on database always "0.0" after i created new record for medic_record.
SOLVED
I has changed method with this and its worked !!
def self.save_tot(medic)
medic.update_attributes(lab_price: Lab.where(:id => medic.lab_ids).reduce(0) { |sum, x| sum += x[:price].to_f })
end

ActiveRecord cannot delete a record

I have my AttachmentsMembers table with the migration as:
class AttachmentsMembers < ActiveRecord::Migration
def change
create_table :attachments_members, :id => false do |t|
t.references :attachment, :null => false
t.references :member, :null => false
end
add_index :attachments_members, [:attachment_id, :member_id]
end
end
If I try to delete any record from my console then I get the following error:
ActiveRecord::StatementInvalid: PG::Error: ERROR: zero-length delimited identifier at or near """"
LINE 1: ...OM "attachments_members" WHERE "attachments_members"."" = $1
^
: DELETE FROM "attachments_members" WHERE "attachments_members"."" = $1
from /home/icicle/.rvm/gems/ruby-2.0.0-p353#ltbuddy/gems/activerecord-3.2.18/lib/active_record/connection_adapters/postgresql_adapter.rb:1208:in `prepare
Code for AttachmentsMember model:
class AttachmentsMember < ActiveRecord::Base
#Relationships
belongs_to :attachment
belongs_to :member
end
In attachment model:
belongs_to :user, class_name: 'User', foreign_key: 'user_id'
belongs_to :attachable, polymorphic: true
belongs_to :referable, polymorphic: true
has_many :attachments, as: :referable, :dependent => :destroy
has_many :attachments_members, :dependent => :destroy
has_many :members, :through => :attachments_members, :dependent => :destroy
In member model:
belongs_to :user, class_name: 'User', foreign_key: 'user_id'
belongs_to :case, class_name: 'Case', foreign_key: 'case_id'
belongs_to :user_type, class_name: 'UserType', foreign_key: 'user_type_id'
has_many :attachments_members, dependent: :destroy
has_many :attachments, :through => :attachments_members, dependent: :destroy
has_many :documents_members, dependent: :destroy
has_many :documents, :through => :documents_members, dependent: :destroy
Even if do AttachmentsMember.last from my console I get the same error but AttachmentsMember.first works.
Any someone explain why the issue is coming?
Resolved the issue by creating the primary key for AttachmentsMember table

public activity and Notifications in rails

i am designing this little application which consists of Users, Activities,Comments and Notifications.
Users has many activities, Comments and notifications. the Activity was designed following ryan bates tutorial of PublicActivity from scratch 407-activity-feed-from-scratch. and also each Activity has many Comments. for the Notifications, it also belongs to the user in such a way that when a Comment is created, a notification is generated, so far my code includes
User Model
class User < ActiveRecord::Base
has_many :comments, :dependent => :destroy
has_many :notifications, :dependent => :destroy
has_many :activities, :dependent => :destroy
end
Activity Model
belongs_to :user
belongs_to :trackable, polymorphic: true
has_many :comments
has_many :notifications
default_scope :order => "activities.created_at DESC"
#scope :recent, where(published_at: Time.now - 2.weeks)
end
Comment Model
class Comment < ActiveRecord::Base
belongs_to :activity
belongs_to :user
default_scope :order => "comments.created_at DESC"
end
Notification Model
class Notification < ActiveRecord::Base
belongs_to :user
belongs_to :activity
end
in the controller,
Comments controller i have tried this
def new
#comment = Comment.new
end
def create
#activity = Activity.find(params[:activity_id])
#comment = #activity.comments.create!(comment_params)
#comment.user = #user
#comment.save
#users= User.joins(:comments).where(comments: {id: #activity.comment_ids}).push(#activity.user).uniq_by {|a| a[:user_id]}
#users.each do |user|
Notification.create(activity_id:#activity, user_id: user.id)
end
redirect_to user_path(current_user)
end
Activity Controller
def index
#activities = Activity.all(:include => :comments, :order => "created_at DESC")
#comments = Comment.find(:all, :order => "created_at DESC")
#comment = Comment.new
#comment.user = current_user
end
Notification Controller
def index
#notifications = current_user.notifications
end
WHAT I WANT TO ACHIEVE IS, NOTIFICATIONS SHOULD BE Created And Available To:
the owner of the activity cos each activity belongs to a particular user i.e when a new comment is created by another user, a notification is available to the owner of the activity.
SHOULD NOT! be available to the new commenter i.e the user that as just commented on the activity but available to owner of the activity
Available to all previous commenters i.e every user that as commented on that activity
and the owner of the activity
. for now my code above does not work and also is there anything am doing wrong with the model and controllers?
basically what i will do is get all Users that commented on the activity with the following
##Activity model
has_many :comments
has_many :users, -> {uniq}, through: :comments
So now your new comment create action will look like this
def create
#activity = Activity.find(params[:activity_id])
#comment = #activity.comments.create!(comment_params)
#comment.user = #user
#comment.save
#users= #activity.users.where("id NOT IN (?)", [#activity.user.id, #comment.user])
## Lets create a notification for all those who created a comment in this activity
#users.each do |user|
Notification.create(activity:#activity, user: user)
end
## Lets create a notification for the owner activity
Notification.create(activity:#activity, user: #activity.user)
redirect_to user_path(current_user)
end
This code is not optimized but can help you out

Associates the same model twice through different name

I am trying to implement a lost and found database.
I have two model, User and Item. A user can lost an an item and found an item. And a item can have a the user who found it and the user who lost it. I want to be able to reference the the same model through different name, e.g.
user.found_items, user.lost_items, item.founder, item.losser
right now I am able to do:
user.founds, user.losts and user.items will return the items from losts
class User < ActiveRecord::Base
has_many :founds
has_many :items, through: :founds
has_many :losts
has_many :items, through: :losts
end
class Lost < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
class Found < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
class Item < ActiveRecord::Base
has_one :found
has_one :user, through: :found
has_one :lost
has_one :user, through: :lost
end
I would do something pretty similar just rename them for clarity and add some methods for the functions you wanted.
class User < ActiveRecord::Base
has_many :found_items
has_many :items, through: :found_item
has_many :lost_items
has_many :items, through: :lost_item
def items_found
self.found_items.map {|i| i.item.name }
end
def items_lost
self.lost_items.map {|i| i.item.name }
end
end
class LostItem < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
class FoundItem < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
class Item < ActiveRecord::Base
has_one :found_item
has_one :user, through: :found_item
has_one :lost_item
has_one :user, through: :lost_item
def finder
self.found_item.user.name
end
def loser
self.lost_item.user.name
end
end

Using a .where IN clause with .includes down and up many nested levels to look up a group of IDs in Rails 3.1

I would like to filter a list of parent emails addresses by a classroom of students.
Here is a simplification of my models:
Class District
has_many :schools
has_many :families
has_many :children, :through => :families
has_many :parents, :through => :families
has_many :enrollments, :through => :children
end
Class Enrollments
belongs_to :child
belongs_to :classroom
end
The email address is associated with the parent record and I would like to filter emails by an array of classroom IDs.
I can get this to work:
idees = [49, 50]
current_district = District.first
#emails = current_district.parents.includes(:family => { :children => { :enrollments => {:classroom => { :program => :location }}}}).where("family_id IN (?)", idees)
# Returns families with ID 49 and 50
But I cannot get anything like this to work
idees = [49, 50]
current_district = District.first
#emails = current_district.parents.includes(:family => { :children => { :enrollments => {:classroom => { :program => :location }}}}).where("family.children.enrollments.classroom_id IN (?)", idees)
# Returns: PGError: ERROR: cross-database references are not implemented: family.children.enrollment.classroom_id
What am I doing wrong or is there another, better way to write this query?
The line below is the problem.
where("family.children.enrollments.classroom_id IN (?)", idees)
Change it to :
where("enrollments.classroom_id IN (?)", idees)