One Association between 3 models in Rails - ruby-on-rails

I am trying to create an association between 3 models where 1 of the models has an association with the other 2 but they have no association with each other. I thought I was one the right track and can create data for the 2 models (breweries and restaurants) but cannot get the third model(beers) to correctly save when used in localhost and will not associate with any other models.
The models are
class Beer < ActiveRecord::Base
belongs_to :brewery
belongs_to :restaurant
validates :brewery, presence: true
validates :restaurant, presence: true
validates :name, presence: true
end
class Brewery < ActiveRecord::Base
has_many :beers
validates :name, presence: true
end
class Restaurant < ActiveRecord::Base
has_many :beers
validates :name, presence: true
end
I also get an error whenever I try to create a new beer through the local host
This is referring to the beers_controllers method.
def create
#brewery = Brewery.find(params[:brewery_id])
#beer = #brewery.beers.create(beer_params)
redirect_to #beer
end
I've tried everything I can think of to no avail and am worried it's just a syntax error that I'm over looking. Would love any advice.

You are getting that error because params[:brewery_id] is nil. Without further information I can only guess but I am thinking that you don't want a beer to belong to both brewery and restaurant. Doing so would require that a beer has both a brewery and a restaurant every time. You probably want something more like a beer has_many beer_venues. A beer has many venues through beer_venues. A venue has many beer_venues. and a venue has many beers through beer_venues. Then You can use single table inheritance on your venues class to give a type column that is either restaurant or brewery.

Related

Rails Models: Where does this object come from?

Following code:
class Product < ApplicationRecord
validates :name, presence: true
validates :price, numericality: {
greater_than_or_equal_to: 0.0
}
validates :description, presence: true
belongs_to :user
def owned_by? owner
user == owner # Where does the user-obj. come from?
end
end
It works. What I don't get is: Where does the "user"-object come from? Please see the line with comment!
"user" is nowhere declared / assigned a value.
Does someone know how that works and can it explain to me?
From the ActiveRecord::Associations::ClassMethods#belongs_to API docs:
Methods will be added for retrieval and query for a single associated
object, for which this object holds an id:
association is a placeholder for the symbol passed as the name
argument, so belongs_to :author would add among others author.nil?.
Example
A Post class declares belongs_to :author, which will add:
Post#author (similar to Author.find(author_id))
...
So in your case, after declaring the belongs_to :user relationship you get that bunch of methods, among them user.

Rails Validation Error on existing data

I am building a simple expenses management app on rails 5.1.4. I am using the following five models.
Payees
class Payee < ApplicationRecord
has_many :expenses
validates :title, uniqueness: true, presence: true
end
Accounts
class Account < ApplicationRecord
before_save :update_balance
validates :balance, numericality: { greater_than_or_equal_to: 0 }
has_many :expenses
end
Budgets
class Budget < ApplicationRecord
belongs_to :categories
has_many :expenses, through: :categories
end
Categories
class Category < ApplicationRecord
validates :title, uniqueness: true, presence: true
has_many :expenses
has_one :budget
end
Expenses
class Expense < ApplicationRecord
belongs_to :categories
belongs_to :budgets
belongs_to :payees
belongs_to :accounts
validates :title, :value, presence: true
before_save :default_account
end
When I try to create a new expense I am facing a validation error
Validation failed: Categories must exist, Budgets must exist, Payees must exist, Accounts must exist
The issue is that all the above records exist. To explain my self let's say I am passing the params account_id: 1, payee_id: 1, category_id: 1. If I do:
Account.find(1) #=> Finds the record
Category.find(1) #=> also ok
Payee.find(1) #=> also ok
I am aware of the solution referred in this question (adding optional: true) but I don't get why I should do that while all of the above exist
Edit
The code that is raising the error is:
def create
#expense = Expense.create!(title: params[:expense]['title'],
value: params[:expense]['value'],
date: params[:expense]['date'],
comment: params[:expense]['comment'],
payee_id: params[:expense]['payee_id'],
category_id: params[:expense]['category_id'],
account_id: params[:expense]['account_id'])
end
The parameters that are passed through the form are
{"utf8"=>"✓",
"authenticity_token"=>"DWd1HEcBC3DhUahfOQcdaY0/oE+VHapxxE+HPUb0I6iSiqMxkz6l+vlK+1zhb66HnZ/vZRUVG4ojTdWUCjHtGg==",
"expense"=>{"title"=>"test", "value"=>"-20", "category_id"=>"1", "payee_id"=>"2", "date"=>"2018-01-21", "account_id"=>"1", "comment"=>""},
"commit"=>"Submit"}
I would first start by commenting out all your model validations, then creating an expense. Add back one model validation at a time, each time test creating an expense to see what validation is causing the error.
also you may want to change how you're creating the expense to something like below.
change your controllers create action to
def create
#expense = Expense.new(expense_params)
if #expense.save
flash[:success] = "expense created"
redirect_to expense_url(#expense.id)
else
render 'new'
end
end
next under your private method at the bottom of your controller you want to do something like this
private
# Never trust parameters from the scary internet, only allow the white list through.
def expense_params
params.require(:expense).permit(:title, :value, :date, etc...)
end
I finally found out where the problem is! It was the naming of the classes/models that raised the error. I had named my models on singular (Account, Category, etc) while all references are searching for plurals ( Accounts, Categories, etc). I had to re-do all migrations from the very beginning in order to make it work the proper way!
Thanks to everyone for spending the time though!

Uniqueness validation of record in polymorphic model in Rails

So I have this big headache trying to solve a bug that only happens sometimes... I have the following model for allowing a user to like something:
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :likeable, polymorphic: true
validates :user, uniqueness: {scope: :likeable}
end
This is a set up to allow a user to like multiple other models and has a validation that prevents a user to like the same thing multiple times.
The thing I discovered after debugging is that the SELECT query run by rails seems to check only for the uniqueness of likeable_id (and not likeable_type):
SELECT 1 AS one FROM "likes" WHERE ("likes"."user_id" = 1 AND "likes"."likeable_id" = 4) LIMIT 1
Logically, when a user had already liked a comment with id is 4, he couldn't like any other thing with the same ID.
Any ideas on how to solve this?
According to the docs, you can define uniqueness validation on both type and id:
http://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of#893-Does-not-work-with-polymorphic-relations
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :likeable, polymorphic: true
validates :user, uniqueness: {scope: [:likeable_id, :likeable_type]}
end

How to validate that a dependent row belongs to a user

I have a model called Category;
class Category < ActiveRecord::Base
belongs_to :user
belongs_to :group
validates :name, presence: true
validates :user_id, presence: true
end
And, I have a model called Group:
class Group < ActiveRecord::Base
belongs_to :user
has_many :categories
validates :name, presence: true
validates :user_id, presence: true
end
As you can see, a group can have many categories. When a user adds a category or updates it's group_id value, I want to check that the group belongs to that user. I don't want users adding to and update categories to another user's group. What is best practise to validate this prior to saving? Thanks
validate :ownership_of_group
def ownership_of_group
ids = []
ids << self.group_id
ids << self.group_id_was if self.group_id_was.present?
if(Group.find(ids).reject {|group| group.user_id == self.user_id}.present?)
# if all of them is owned by the user the array will return an empty array
errors.add(:user_id, 'You cant edit a category that is not yours')
end
end
If we say group_id we get the current value that is being set by the use.
If we say group_id_was it get the old value before the update.
In the update we need to handle both in the create we have no previous value.

how to join from a belongs_to model to a has_many table from the controller or view?

I have two very simple models, Clients and Appointments:
class Client < ActiveRecord::Base
validates :first_name, presence: true
validates :last_name, presence: true
validates :copay, numericality: { only_integer: true }
has_many :appointments
end
class Appointment < ActiveRecord::Base
belongs_to :clients
end
What I'd like to do is show all of the Clients that have appointments in the index page. It makes more sense to me to try to do this through the Applications controller. Something like this:
def index
#appointments = Appointment.client.all
end
But I can't quite figure out the right way to do it. In the Clients controller it makes sense to do something like this:
#clients = Client.all(:include => :appointments)
What's the way to do the reverse (i.e. pull clients into appointments)?
This will give you all clients that have appointments:
#clients = Client.joins(:appointments)
I don't think it makes sense at all to do this in your ApplicationController. Since you want to display that list in a specific page, you should do it in clients#index or appointments#index.

Resources