Association not creating methods - ruby-on-rails

I have User, Guide, and CityObj models. User has one Guide, and Guide belongs to User. This allows me to use methods to access the parent from the child and vice versa:
a_user.guide
a_guide.user
But these methods aren't there for CityObj:
a_guide.cityobj ----> error
a_cityobj.guide ----> error
Maybe it has to do with the camel case? It seems like I'm doing the same thing for User/Guide and Guide/CityObj.
User.rb
class User < ActiveRecord::Base
has_one :guide, dependent: :destroy
...
end
Guide.rb
class Guide < ActiveRecord::Base
has_one :cityObj, dependent: :destroy
belongs_to :user
...
end
CityObj.rb
class CityObj < ActiveRecord::Base
belongs_to :guide
end

As per convention, you should use snake case
a_guide.cityobj
a_cityobj.guide
should be
a_guide.city_obj
a_city_obj.guide
Also, change your association in guide.rb model to below.
#guide.rb
has_one :city_obj, dependent: :destroy

As #Pavan said the convention should be snake case, including for the filenames and the association definition (and methods in general)
CitObj.rb should be city_obj.rb
User.rb should be user.rb
Also :
class Guide < ActiveRecord::Base
has_one :city_obj, dependent: :destroy
belongs_to :user
# ...
end
This will "generate" association methods like : build_city_obj etc...

Related

Guarantee that model is associated to same parent

Assuming i have 3 models associated to each other:
class Farm < ApplicationRecord
has_many :horses
has_many :events
end
class Horse < ApplicationRecord
belongs_to :farm
has_many :events_horses, class_name: 'Event::EventsHorse'
has_many :events, through: :events_horses, source: :event, dependent: :destroy
end
class Event
belongs_to :farm
has_many :events_horses, class_name: 'Event::EventsHorse'
has_many :horses, through: :events_horses, source: :horse, dependent: :destroy
end
class Event::EventsHorse < ApplicationRecord
self.table_name = "events_horses"
belongs_to :horse
belongs_to :event
audited associated_with: :event, except: [:id, :event_id]
end
How to guarantee that each of the Horse belongs to same Farm as event? Possible solution is using custom validation, but i was wondering if there is some other way. I have few other models like Horse, so it force me to do custom validation method to each of them.
class Event
...
validate :horses_belongs_to_farm
private
def horses_belongs_to_farm
horses.all? {|h| h.farm_id == farm_id}
end
end
I think the model you are using is setting up too many id's between the tables that require consistency checking.
If you set the model up this way, then you don't need to validate that a horse's farm and event are consistent since the data ensures it:
class Farm < ApplicationRecord
has_many :horses
has_many :events
end
class Horse < ApplicationRecord
belongs_to :farm
has_many :events, through: :farm
end
class Event < ApplicationRecord
belongs_to :farm
has_many :horses, through: :farm
end
If you need efficient access to horses from events or events from horses, you can use joins. This gives some simplicity, clarity, and consistency.
You should also have a look at Choosing Between has_many_through and has_and_belongs_to_many.
[Edit based upon updated question and comments] Now that your model and question are a little more clear, my hunch is that putting the validation in the Event model causes redundant validations. Since your intent is to make sure that, in a given event, the horse and farm are consistent, I would put the validation in EventsHorses:
class Event::EventsHorse < ApplicationRecord
...
validate :horse_belongs_to_farm
private
def horse_belongs_to_farm
horse.farm_id == event.farm_id
end
end
As an aside, thy do you have Event::EventsHorse rather than simply have a separate model for EventsHorse?

Rails has_many :through #new doesn't set associations on new record

As per the Rails docs, one can use has_many :through as a shortcut:
The has_many :through association is also useful for setting up
"shortcuts" through nested has_many associations. For example, if a
document has many sections, and a section has many paragraphs, you may
sometimes want to get a simple collection of all paragraphs in the
document.
So let's say we have this code:
class User < ApplicationRecord
has_many :sub_users
has_many :settings
end
class SubUser < ApplicationRecord
belongs_to :user
has_many :settings, through: :user
end
class Setting < ApplicationRecord
belongs_to :user
end
Based on this, if I run user.settings.new, I get a new Setting instance with user_id set to user.id.
That's great. But if I run sub_user.settings.new, I get a new Setting instance that doesn't have user_id set to sub_user.user.id.
Is this expected behavior?
I wouldn't use has_many through: for that, delegate looks like the best idea https://apidock.com/rails/Module/delegate
class SubUser < ApplicationRecord
belongs_to :user
delegate :settings, to: :user
end
Your current code is not what has_many through is for, check the docks, the relations are different https://guides.rubyonrails.org/association_basics.html#the-has-many-through-association

Associate Rails active model with two different models

Is there a way to use inheritance with Ruby on Rails Active Model?
I have two models to which I want to add comments. It would be cool if I can just use one Comment model that could be associated with both models.
Look into Polymorphic Associations
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class Article < ApplicationRecord
has_many :comments, as: :commentable
end
class Image < ApplicationRecord
has_many :comments, as: :commentable
end

How to define a nested has_one association?

Suppose we have this contrived model structure
class Apple < ActiveRecord::Base
belongs_to :fruit
has_one :tree, through: :fruit
has_one :organism, through: :tree
end
class Fruit < ActiveRecord::Base
belongs_to :tree
has_many :apples
end
class Tree < ActiveRecord::Base
belongs_to :organism
has_many :fruits
end
class Organism < ActiveRecord::Base
has_many :trees
end
To avoid having to call #apple.fruit.tree.organism, I have definded the two has_one-through directives in Apple, and expect #apple.organism to work, but it does not. #apple.tree.organism does work.
Am I doing something wrong? Should I just define a getter method for :organism on Apple instances and be done with it?
Your has_one technically performs the characteristic of belongs_to: think Organism has_many apples through trees and not the other way around. "belongs_to :through" does not work in Rails, so I suggest using delegate in your models.
class Apple < ActiveRecord::Base
delegate :organism, to: :fruit
end
class Fruit < ActiveRecord::Base
delegate :organism, to :tree
end

Rails relationships setup for 5 table db

I'm stuck in a circle of indecision and need a shove to break free. I'm a noob with Rails and I'm attempting to translate a pre-existing database using Rails conventions. Basically, I currently have 5 models/tables: Workorders, Mileage_logs, Time_logs, Parts, & Equipment. A Workorder can have many Mileage_logs, Time_logs, and Parts, because each of them is shown on the Workorder's index page. But, that's the seemingly easy part...
I'm getting confused when the Equipment model is introduced because it seems like it's basically the same thing as the Workorder.
What is the best way to handle this relationship setup? Is this an appropriate use for the has_many :through convention? Or, is this best done with simply having the workorder_id and equipment_id in the Mileage_log, Time_log, and Part models and then:
class Part < ActiveRecord::Base
belongs_to :workorder
belongs_to :equipment
end
class Mileage_log < ActiveRecord::Base
belongs_to :workorder
belongs_to :equipment
end
class Time_log < ActiveRecord::Base
belongs_to :workorder
belongs_to :equipment
end
class Workorder < ActiveRecord::Base
has_many :Time_logs
has_many :Parts
has_many :Mileage_logs
end
class Equipment < ActiveRecord::Base
has_many :Time_logs
has_many :Parts
has_many :Mileage_logs
end
Or, is the has_many through: relationship what I should look into for the Workorder & Equipment models?
class Workorder < ActiveRecord::Base
has_many :parts
has_many :mileage_logs
has_many :time_logs
end
class Equipment < ActiveRecord::Base
has_many :parts, through: :workorder
has_many :mileage_logs, through: :workorder
has_many :time_logs, through: :workorder
has_many :workorders
end
Any help would be greatly appreciated!
Also, any general advice on the route setup would be welcomed as well.

Resources