Rails 3: calling database on a has_many association - ruby-on-rails

Hi I have a many to many association where 'posts' have many 'feeling', I'd like to figure out how to find all the posts with a specific feeling by the user. My Feeling model has a 'name' attribute.
class User < ActiveRecord::Base
has_many :posts, :dependent => :destroy
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
class Post < ActiveRecord::Base
has_many :feelingships
has_many :feelings, :through => :feelingships
belongs_to :user
end
class Feeling < ActiveRecord::Base
has_many :feelingships
has_many :posts, :through => :feelingships
end
class Feelingship < ActiveRecord::Base
belongs_to :post
belongs_to :feeling
attr_accessible :post_id, :feeling_id
end
I tried this but it says I have the wrong association: "ActiveRecord::ConfigurationError: Association named 'feeling' was not found; perhaps you misspelled it?"
def feeling
#user = User.find(params[:id])
#feed_items= #user.posts.includes(:feeling).where(
['`feelings`.name = ?', params[:feeling]])
#feed_items = #feed_items.paginate(:per_page => "10", :page => params[:page])
render 'shared/_feed', :layout => 'head_layout'
end

The includes argument should be :feelings - notice the plural, which is what your association is named.
So it should be:
#user.posts.includes(:feelings)

Related

Querying for values from several models

I have a Course and Lesson models. Course has several lessons. I want to find all the lessons for currently logged in student to generate kind of timetable.
I have a method that returns all the courses that this student is studying. Now I want to get all lessons from all those courses in #courses into #lessons, something like:
def index
#courses = current_student.find_courses
#lessons = #courses.lessons
end
Is it possible to do it somehow simple on one line?
The find_courses method is implemented as following:
def find_courses
Course.where("id IN (?)", StudentAssignment.select("course_id").where('student_id == (?)', self.id))
end
The Models:
class Student < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :student_assignments
has_many :courses, :through => :student_assignments
....
class Lesson < ApplicationRecord
belongs_to :room
belongs_to :teacher
belongs_to :course
....
class Course < ApplicationRecord
has_many :lessons, dependent: :destroy
has_many :teacher_assignments
has_many :teachers, :through => :teacher_assignments
has_many :student_assignments
has_many :students, :through => :student_assignments
...
class Student < ApplicationRecord
has_many :courses
def active_lessions
Lession.joins(course: :students).where(students: {id: self.id})
end
end
In this way you can directly get all active lesssions for current_user
current_student.active_lessions
Try:
#lessons = #courses.flat_map(&:lessons)
It takes each course in #courses list and gets the list of lessons for that course.

Creating a favorite list in rails with devise

i have a problem to solve in my application here a little brief:
My app is something like AirBnb so i have Users and Houses, any user can create a house i already have this, i need a watch list, is a list of houses who user liked like a Bookmark or Favorite system, i have the house list and the idea is have button like "watch this" when user clicks this house go to their watch lists.
I've seen many solutions and i tried them, i understand the relationship but i don't know how do get pieces in.
here is my code currently:
watch.rb:
class Watch < ActiveRecord::Base
belongs_to :user
belongs_to :house
end
user.rb:
class User < ActiveRecord::Base
has_many :houses, :dependent => :destroy
has_many :watches, :dependent => :destroy
has_many :watch_houses, :through => :watches, :source => :houses
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
house.rb:
class House < ActiveRecord::Base
belongs_to :user
has_many :watches, :dependent => :destroy
has_many :watches, :through => :watches, :source => :user
end
routes.rb:
Rails.application.routes.draw do
resources :houses
devise_for :users
resources :users, :only => [:show] do
resources :watches
end
resources :houses
root 'home#index'
end
How can i create a link to assing the user and the house in the watchlist cliking in the house list?
Here's how to do it:
#config/routes.rb
resources :houses do
post :watch #-> url.com/houses/:house_id/watch
end
#app/controllers/houses_controller.rb
class HousesController < ApplicationController
def watch
#house = House.find params[:house_id]
current_user.watched_houses << #house
redirect_to #house, notice: "Added to Watch List"
end
end
Here are the models:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :houses, dependent: :destroy
has_many :watching, class_name: "Watch", foreign_key: :user_id, dependent: :destroy
has_many :watched_houses, through: :watching
end
#app/models/house.rb
class House < ActiveRecord::Base
belongs_to :user
has_many :watches, dependent: :destroy
has_many :watchers, through: :watches, foreign_key: :user_id
end

Rails 4:How to make users view only files in their own office

I am creating a file tracking system whereby users can track the movement from one office to another. I've gotten most of the application to work but presently every user can view all files regardless of where it's in their office, or not because in the file index.
I am using File.all in my file index action. Is there a way I can have a user only view and track files that is only currently in their own office, while the registry officer(admin) can view and track all files?
My relationships between models:
File model
class Nasfile < ActiveRecord::Base
belongs_to :category
has_many :trackers, dependent: :destroy
before_save :file_full_number, :on => [:create, :update]
def file_full_number
if self.file_sub.present?
self.file_number = [self.file_number , self.file_sub].join('/')
else
self.file_number = self.file_number
end
end
end
Office Model
class Office < ActiveRecord::Base
belongs_to :department
has_many :users
has_many :received_files,:class_name => 'Tracker', :foreign_key => 'office_sent_to_id'
has_many :sent_files,:class_name => 'Tracker', :foreign_key => 'office_sent_from_id'
def self.all_without(excluded)
where("id NOT IN (?)", excluded)
end
end
Tracker Model
class Tracker < ActiveRecord::Base
belongs_to :nasfile
belongs_to :sender, :foreign_key => :sender_id, class_name: 'User'
belongs_to :receiver, :foreign_key => :receiver_id, class_name: 'User'
belongs_to :office_receiving, :foreign_key => :office_sent_to_id, class_name: 'Office'
belongs_to :office_sending, :foreign_key => :office_sent_from_id, class_name: 'Office'
before_save :office_sent_to, :on => [:create, :update]
def office_sent_to
self.office_sent_to_id = self.receiver.office.id
end
end
User model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable,:recoverable
devise :database_authenticatable, :registerable,
:rememberable, :trackable, :validatable,
:authentication_keys => [:username], password_length: 6..25
belongs_to :office
accepts_nested_attributes_for :office
has_many :sent_files,:class_name => 'Tracker', :foreign_key => 'sender_id'
has_many :received_files,:class_name => 'Tracker', :foreign_key => 'receiver_id'
def email_required?
false
end
def email_changed?
false
end
def self.all_without(excluded)
where("id NOT IN (?)", excluded)
end
end
Thanks for the help
Rather than doing
#files = File.all
try to filter the files you include by doing something like:
#files = File.where("office_id = ?", current_user.office_id)
This way, you only get files for the office to which the user belongs.
I don't know how you have your roles set up, but you can add some branching logic to allow registry officers to see all files, regardless of office:
if user.role = "registry officer"
#files = File.all
else
#files = File.where("office_id = ?", current_user.office_id)
end

Trouble writing action

UPDATE
I have an action in my Miniatures model called set_gold_and_silver.
I want my Users model to run it when a User is destroyed, so I have before_destroy :set_gold_and_silver in my User model.
A User has many Imagevotes. Before destroy I need to delete those Imagevotes and then run set_gold_and_silver on all the Miniatures that those imagevotes pertained to.
This is what I've got so far and I'm currently getting undefined method 'miniatures'.
It's not clear to me whether I am caching self.imagevotes or whether they are just deleted and then I get the error because they no longer exist?
def set_gold_and_silver
votes = self.imagevotes
self.imagevotes.destroy
votes.miniatures.uniq.each(&:set_gold_and_silver)
end
My models
User
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
has_many :collections, dependent: :destroy
has_many :miniatures, through: :collections
has_many :imagevotes, foreign_key: "voted_id", dependent: :destroy
has_many :imagevotes, foreign_key: "voter_id", dependent: :destroy
before_destroy :set_gold_and_silver
def set_gold_and_silver
my_collections = self.collections.each
their_miniatures = collection.miniature.uniq
my_collections.their_miniatures.each(&:set_gold_and_silver)
end
end
Miniature
class Miniature < ActiveRecord::Base
has_many :collections, dependent: :destroy
has_many :users, :through => :collections
has_many :imagevotes, dependent: :destroy
def set_gold_and_silver
wipe = self.collections.all
wipe.each {|s| s.update_attributes :is_gold => false, :is_silver => false}
top_collections = self.collections.limit(4)
gold = top_collections.shift
gold.update_attribute :is_gold, true if gold
top_collections.each {|s| s.update_attribute :is_silver, true}
end
end
Collection
class Collection < ActiveRecord::Base
default_scope order('imagevotes_count DESC')
belongs_to :miniature
belongs_to :user
has_many :imagevotes, dependent: :destroy
end
Imagevote
class Imagevote < ActiveRecord::Base
belongs_to :collection, :counter_cache => true
belongs_to :voter, class_name: "User", :counter_cache => "voted_count"
belongs_to :voted, class_name: "User", :counter_cache => "vote_count"
belongs_to :miniature
after_create :set_gold_and_silver
after_update :set_gold_and_silver
def set_gold_and_silver
self.miniature.set_gold_and_silver
end
end
You need to make your code simpler:
class Miniature < ActiveRecord::Base
def set_gold_and_silver
self.collections.update_all("is_gold = false, is_silver = false")
top_collections = self.collections.limit(4)
gold = top_collections.shift
gold.update_attribute :is_gold, true if gold
top_collections.each {|s| s.update_attribute :is_silver, true}
end
end
class User < ActiveRecord::Base
def set_gold_and_silver
self.miniatures.uniq.each(&:set_gold_and_silver)
end
end
you have has_many :miniatures, through: :collections so you don't need to work with collections to get minuatures.
And for now your code not working because everything still there before destroy. It need to be done after, when everything depended to user removed. And also as it seems for me you need to remove imagevotes in user destroy and set_gold_and_silver only after that. For now it's not done, so gold and silver stays.

How to 'subscribe' an user to an existing instance of this Tag model instead of creating a new one?

I have a Post model:
class Post < ActiveRecord::Base
attr_accessible :title, :content, :tag_names
belongs_to :user
has_many :taggings, :dependent => :destroy
has_many :tags, :through => :taggings
attr_writer :tag_names
after_save :assign_tags
def tag_names
#tag_names || tags.map(&:name).join(' ')
end
private
def assign_tags
if #tag_names
self.tags = #tag_names.split(" ").map do |name|
Tag.find_or_create_by_name(name)
end
end
end
end
a Tag model:
class Tag < ActiveRecord::Base
has_many :taggings, :dependent => :destroy
has_many :posts, :through => :taggings
has_many :subscriptions
has_many :subscribed_users, :source => :user, :through => :subscriptions
end
and an User model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :avatar
has_many :posts, :dependent => :destroy
has_many :subscriptions
has_many :subscribed_tags, :source => :tag, :through => :subscriptions
end
posts and tags have a many-to-many relationship (the following is the model for the join table):
class Tagging < ActiveRecord::Base
belongs_to :post
belongs_to :tag
end
users and tags have also a many-to-many relationship:
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :tag
end
Only posts with tags that the user has subscribed to should display:
def index
#title = "Posts"
#posts = current_user.subscribed_tags.map(&:posts).flatten.paginate(:page => params[:page], :per_page => 5)
Let say I create a tag for a post:
$ post.tags.create(:name => "food")
$ post.tags
=> [#<Tag id: 6, name: "food", created_at: "2012-03-02 10:03:59", updated_at: "2012-03-02 10:03:59"]
Now I have no idea how to subscribe the user to that tag.
I tried this:
$ user.subscribed_tags.create(:name => "food")
$ post.tags
=> [#<Tag id: 7, name: "food", created_at: "2012-03-02 10:04:38", updated_at: "2012-03-02 10:04:38"]
But as you can see it actually creates a new tag instead of adding the food tag with ID 6 to the user.subscribed_tags attribute.
Any suggestions to solve this issue?
You can append to the user's subscriped_tags, as you would do an array.
ex: user.subscribed_tags << Tag.find_by_name("food")

Resources