I have the following models:
class Department < ApplicationRecord
has_many :department_job_titles
has_many :job_titles, through: :department_job_titles
end
class JobTitle < ApplicationRecord
has_and_belongs_to_many :departments
end
class DepartmentJobTitle < ApplicationRecord
belongs_to :department
belongs_to :job_title
validates :department_id, uniqueness: { scope: :job_title_id }
end
This is erring w PG::UndefinedColumn: ERROR: column department_job_titles.title does not exist
LINE 1: ... "department_job_titles"."department_id" = $1 AND "departmen...
Department.first.department_job_titles.find_or_create_by(title: title)
DepartmentJobTitle has the following fields: id, department_id, job_title_id
What am I doing wrong here?
Try this:
job_title = JobTitle.find_or_create_by(title: title)
Department.first.job_titles << job_title unless job_title.in? Department.first.job_titles
Or that second line could be:
Department.first.job_titles = (Department.first.job_titles + [job_title]).uniq
Also:
class JobTitle < ApplicationRecord
has_many :department_job_titles
has_many :departments, through: :department_job_titles
end
... and ...
class DepartmentJobTitle < ApplicationRecord
belongs_to :department
belongs_to :job_title
validates :department, presence: true, uniqueness: { scope: :job_title }
validates :job_title, presence: true
end
... and think about what behaviour you want if someone destroys a JobTitle or Department -- either you want the DepartmentJobTitle destroyed also, or you want the destroy to be prevented, I expect.
Related
I'm trying to build a query such that if a driver sends an offer to a ride, that ride no longer shows up in the collection rendered in the index view.
I've tried so many variations and I'm still getting all the rides. Even the ones Ive sent an offer to.
lang - ruby
class Driver < ApplicationRecord
belongs_to :user
has_many :offers
has_many :rides
end
class User < ApplicationRecord
has_many :rides
has_one :driver
end
class Ride < ApplicationRecord
validates :to, presence: true
validates :from, presence: true
validates :directions_from, presence: true
has_many :offers
belongs_to :user
belongs_to :driver, optional: true
end
lang - ruby
class Driver < ApplicationRecord
belongs_to :user
has_many :offers
has_many :rides
end
class User < ApplicationRecord
has_many :rides
has_one :driver
end
class Ride < ApplicationRecord
validates :to, presence: true
validates :from, presence: true
validates :directions_from, presence: true
has_many :offers
belongs_to :user
belongs_to :driver, optional: true
end
class Offer < ApplicationRecord
belongs_to :ride
belongs_to :driver
end
def index
#location = current_user.currently_at
#rides = Ride.includes(:driver).where(from: #location).select do |ride|
ride.offers.map do |offer|
offer.driver.user != current_user
end
end
#offer = Offer.new
end
I have 3 main models in my program; User, Country, City.
User and Country have a many-to-many relationship, which I join with
a Trip model.
User and City have a many-to-many relationship, which I join with a
Visit model.
Country and City have a one-to-many relationship.
When I run rails db:migrate I get no errors and all appears well, however when I try and seed data or go into the console to create a City it will not save. Any Users or Countries will be successfully created and I am able to build relationships between them.
See my models below.
user.rb
class User < ApplicationRecord
before_save { self.email = email.downcase }
#attr_accessible :user_name, :email
validates_confirmation_of :password
has_secure_password
validates :user_name, presence: true, length: { maximum: 25 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }
validates :password, presence: true, confirmation: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
has_many :trips
has_many :visits
has_many :countries, through: :trips
has_many :cities, through: :visits
end
city.rb
class City < ApplicationRecord
has_many :visits
has_many :users, through: :visits
belongs_to :country
end
country.rb
class Country < ApplicationRecord
has_many :trips
has_many :cities
has_many :users, through: :trips
end
trip.rb
class Trip < ApplicationRecord
belongs_to :country
belongs_to :user
end
visit.rb
class Visit < ApplicationRecord
belongs_to :city
belongs_to :user
end
Originally I did not even have the Visit model, I just joined both many-to-many relationships through the Trip model. However, in trying to solve the issue I separated it.
Any help with this issue would be appreciated. If you need more information just let me know.
I would start by modeling it properly:
class City < ApplicationRecord
has_many :visits
has_many :users, through: :visits
belongs_to :country
end
class Country < ApplicationRecord
has_many :trips
has_many :cities
has_many :users, through: :trips
end
class Trip < ApplicationRecord
belongs_to :country
belongs_to :user
has_many :visits
has_many :cities, through: :visits
end
class Visit < ApplicationRecord
belongs_to :trip
belongs_to :city
has_one :country, through: :city
has_one :user, through: :trip
end
# added
class User < ApplicationRecord
# ...
has_many :trips
has_many :visits, through: :trips
has_many :countries, through: :trips
has_many :cities, through: :visits
end
This creates a one to many association between Trip and Visit and avoids duplicating the user_id foreign key on both.
In Rails 5 one of the major changes is that belongs_to associations are non-optional by default.
So if you attempt to create a city without a country the validations will fail. But if you create the city from an existing record:
Country.first.cities.create!(name: 'Toronto')
Or pass a record:
City.create!(name: 'Toronto', country: Country.first)
The validation will pass.
You can also set the association as optional which is the behaviour in Rails 4:
class City < ApplicationRecord
has_many :visits
has_many :users, through: :visits
belongs_to :country, optional: true
end
as city has_many users through visits, then you have to declare has_many :visits inside city model below is sample code probably can help you problem
class City < ApplicationRecord
has_many :visits
has_many :users, through: :visits
belongs_to :country
end
when you create city in your console, make sure you gave country_id as in belongs_to country, here is a sample code:
#city = City.new
#city.country = Country.first
# #city.name = .... # your seed code
#city.save
I have 2 Models: Post, User. The User cannot like his post, so how can i prevent creating the instance of the Model Like (user_id: creator, post_id:created by the "creator") ?
You can validate that in your Like model:
class Like < ActiveRecord::Base
validates_presence_of :user_id, :post_id
validate :voter_not_author
private
def voter_not_author
if self.user_id == self.post.try(:user_id)
self.errors[:base] << "Author can't be the voter"
end
end
end
Another implementation I found...
#app/models/like.rb
class Like < ActiveRecord::Base
validates :user_id, exclusion: {in: ->(u) { [Post.find(u.post_id).user_id] }} #-> user_id cannot equal post.user_id
end
If you wanted to get rid of the db query, you'd have to associate the models and use inverse_of:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :likes
end
#app/models/like.rb
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :post, inverse_of: :likes
validates :user_id, exclusion: {in: ->(u) { u.post.user_id }}
end
#app/models/post.rb
class Post < ActiveRecord::Base
has_many :likes, inverse_of: :post
end
I am attempting to do a query via a junction table, though Rails is given me the below error
Venue Model
class Venue < ActiveRecord::Base
attr_accessible :address, :latitude, :longitude, :name, :phone, :suburb, :state, :country
after_validation :geocode
has_many :orders, through: :venues_orders
geocoded_by :full_address
def full_address
[address, suburb, state, country].compact.join(', ')
end
end
Order Model
class Order < ActiveRecord::Base
attr_accessible :fulfilled, :item, :placed, :person_id, :special_instructions, :priority, :flag, :milk
belongs_to :person
belongs_to :venue
Venues Orders Model
class VenuesOrders < ActiveRecord::Base
attr_accessible :order_id, :venue_id
end
class Venue < ActiveRecord::Base
has_many :orders, through: :venues_orders
has_many :venues_orders
end
class Order < ActiveRecord::Base
has_many :venues, through: :venues_orders
has_many :venues_orders
end
class VenuesOrders < ActiveRecord::Base
belongs_to :venue
belongs_to :order
end
For more details read : RailsGuides
Another advice: The convention for creating a join table is lexical ordering. Like, OrdersVenues not VenuesOrders
In my project i have something like this:
class User < ActiveRecord::Base
has_many :roles
has_many :websites, through: :roles
end
class Website < ActiveRecord::Base
validates :name, presence: true
has_many :roles
has_many :users, through: :roles
end
class Role < ActiveRecord::Base
validates :name, presence: true
belongs_to :user
belongs_to :website
end
So when I try to do:
User.first.websites.create(name: "First")
I have this error
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
How can i create a new User Website in one line?
The validation error is actually coming from the Role model, which also has validation for the name attribute.
You can do it in one line by creating the website through the role, using accepts_nested_attributes_for:
class Role < ActiveRecord::Base
validates :name, presence: true
belongs_to :user
belongs_to :website
accepts_nested_attributes_for :website
end
User.first.roles.create(name: "Role name", website_attributes: { name: "Website name" })
I think if you remove validates :name, presence: true from role model then it will work.