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
Related
In the context where a user.admin has_many hotels, is there a way to invite a user to 1 hotel only? (e.g. many-to-many relationship between user and hotel, with join UserHotel table).
More concretely, the first problem I am encountering is that I am not able to properly insert the hotel_id param in the users/invitations_controller.
Error message:Couldn't find Hotel without an ID. params sent: {"format"=>"109"}
Please find my current code below=>
views/hotels/show
<%= link_to "invite new user", new_user_invitation_path(#hotel) %>
routes
Rails.application.routes.draw do
devise_for :users, controllers: {
invitations: 'users/invitations'
}
resources :hotels do
resources :users
end
end
models
class User < ApplicationRecord
has_many :user_hotels, dependent: :destroy
has_many :hotels, through: :user_hotels
enum role: [:owner, :admin, :employee]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :admin
end
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :invitable
end
class UserHotel < ApplicationRecord
belongs_to :hotel
belongs_to :user
end
class Hotel < ApplicationRecord
has_many :user_hotels, dependent: :destroy
has_many :users, through: :user_hotels
accepts_nested_attributes_for :users, allow_destroy: true, reject_if: ->(attrs) { attrs['email'].blank? || attrs['role'].blank?}
end
controllers/users/invitations
class Users::InvitationsController < Devise::InvitationsController
def new
#hotel = Hotel.find(params[:hotel_id])
#user = User.new
How to build the join table UserHotel when inviting?
end
end
add this code to app/models/user.rb:
accepts_nested_attributes_for :user_hotels
and then:
User.new(user_hotels_attributes: [{ hotel: #hotel }])
you can add your own validations to prevent duplicate entry.
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
Here is my join model:
class CompanyUser < ActiveRecord::Base
belongs_to :company
belongs_to :user
end
My User model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
ROLES = %w[admin requestor requestor_limited shipping_vendor].freeze
attr_accessor :temp_password
has_many :companies_users
...
end
If I run this in the console:
u = User.first
u.companies
This is the error I am getting:
NameError: uninitialized constant User::CompaniesUser
has_many through relationships should be like this:
In app/models/company.rb file,
has_many :company_users
has_many :users, :through => :company_users
In app/models/user.rb file,
has_many :company_users
has_many :companies, :through => :company_users
In app/models/company_user.rb file,
belongs_to :company
belongs_to :user
If you want to delete the dependent records in company_users table when deleting companies/users,
Add, , :dependent => :destroy at the end of has_many relations in Company and User model.
Hope this helps you..
Thanks.!!
it must be
has_many :company_users
"CompanyUser".tableize => "company_users"
The model shall be either:
class CompaniesUser < ActiveRecord::Base
belongs_to :company
belongs_to :user
end
Or has_many declaration sheel be defined explicitly as:
class User < ActiveRecord::Base
has_many :company_users
end
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.
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)