Structuring associations Rails 4 - ruby-on-rails

This is probably a fairly straight forward answer that I feel like I should know, but occasionally I run across something like this that stumps me.
I'm working on a rails app that requires me to essentially create a leasing system for rentals.
I've got a user, a building, a lease and an unit. The way I've got it structured right now is:
class Buildings < ActiveRecord::Base
has_many :units
has_many :users
end
class User < ActiveRecord::Base
belongs_to :buildings
has_many :units, through :lease
end
class Lease < ActiveRecord::Base
belongs_to :user
belongs_to :unit
end
class Unit < ActiveRecord::Base
belongs_to :building
belongs_to :user
has_one :lease
end
I'm running into syntax errors and association errors and the documentation is as clear as mud. Perhaps someone can help me to properly structure these associations.

Your syntax error is on the User class
Change
has_many :units, through :lease
to
has_many :unit, through: :lease
or
has_many :units, :through => :lease

Related

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.

issue with has_many, through association

For some reason, my has_many through association isn't working. Here are my models:
class Interest < ActiveRecord::Base
has_many :evints
has_many :events, through: :evints
has_many :images, through: :events
end
class Event < ActiveRecord::Base
has_many :evints
has_many :images
has_many :interests, through: :evints
end
class Evint < ActiveRecord::Base
belongs_to :events
belongs_to :interests
end
The Evints table has three columns: interest_id, event_id, and id.
When I call #interest.events, I get the error message
uninitialized constant Interest::Events
Obviously, there's something going wrong with the association if #interest.events is being read as a constant!
Does anyone have any ideas?
Thanks!
Check your Evint class, it should be:
class Evint < ActiveRecord::Base
belongs_to :event
belongs_to :interest
end
On a different note, I think Evint isn't really a very good name. It'd suggest that you go with EventInterest, and name the table event_interests.

Rails 4 has_many through many

I'm stuck on this:
class Worker < ActiveRecord::Base
has_many :skills
has_many :jobs, through: :skills
..
end
class Skill < ActiveRecord::Base
belongs_to :worker
has_many :jobs
..
end
class Job < ActiveRecord::Base
has_many :skills
has_many :workers, through: :skills
..
end
What I'm trying to do is set up a many to many between Skill and Job inside of the `has_many' through relationship?
My question has three parts
Is this possible - using the has_many jobs rather than belongs_to jobs.
If it can be done and the code is wrong, how do I fix it?
How can I create Worker, Skill and Job records? (looking for syntax)
This is a picture (of sorts) of what I'm trying to do, hope it helps... :(
You're not giving active record enough information about your relationships. Every :has_many should have a corresponding :belongs_to so that active record knows which table holds the foreign key for each association. Notice that you only have one :belongs_to for three relationships. That smells.
As for fixing the problem, you have at least 2 options:
add :has_and_belongs_to_many associations
use explicit join tables
My preference is for the latter option. Being forced to name join tables often clarifies the nature of a relationship. On the flip side, I've found that :has_and_belongs_to_many is often too implicit and ends up making my designs more obscure.
Explicit join tables
You might setup your relationships like this (untested):
class Assignment < ActiveRecord::Base
belongs_to :worker
belongs_to :job
end
class Qualification < ActiveRecord::Base
belongs_to :worker
belongs_to :skill
end
class Worker < ActiveRecord::Base
has_many :qualifications
has_many :skills, through: :qualifications
has_many :assignments
has_many :jobs, through: :assignments
..
end
class Skill < ActiveRecord::Base
has_many :qualifications
has_many :workers, through: :qualifications
has_many :jobs
..
end
class Job < ActiveRecord::Base
has_many :skills
has_many :workers, through: :assignments
..
end
By making the relationships more explicit I think the model is clearer. It should be easier to troubleshoot from here.
EDIT:
If you need to do a traversal like Job.find(1).qualified_workers try making the following adjustment to the above model:
class Job
has_many :required_competencies
has_many :skills, through: :required_competencies
has_many :qualifications, through: :skills
has_many :qualified_workers, through: qualifications, class_name: :workers
end
class RequiredCompetency
belongs_to :job
belongs_to :skill
end
This is explicit about each traversal and names it. If you find these paths through your system are getting really long, I'd consider that a smell. There might be a more direct way to fetch your data or perhaps a better way to model it.

Importing csv file to nested resource models (has_many :through etc.)

I hope that someone can help me with importing csv file into nested resource model.
I have a couple of models (Rails 4.0, Ruby 2.0):
class Level < ActiveRecord::Base
belongs_to :level_type
has_many :project_levels
has_many :projects, through: :project_levels
end
class LevelType < ActiveRecord::Base
has_many :levels
end
class ProjectLevel < ActiveRecord::Base
belongs_to :level
belongs_to :project
end
class Project < ActiveRecord::Base
belongs_to :company
has_many :project_levels
has_many :levels, through: :project_levels
end
class Company < ActiveRecord::Base
has_many :projects
end
And what I do similar to this in a rake task:
company.projects.create(company_name: row[3])
level_type.levels.create(position: row[4])
My problems is how to create levels from companies? Is this the right thing to do?
company.projects.levels.create(company_name: row[3])
What is confusing me is that I have 2 sides to get to the levels and the same information I have to put into it (company_name: row[3]) and I am not sure how to deal with it. Any help would be appreciated.

Rails has_many :though STI

Lets start with code that may go like this:
class User < ActiveRecord::Base
has_many :photos
has_many :submitted_photos
has_many :posted_photos
has_many :handshakes, through: :photos
end
class Photo < ActiveRecord::Base
belongs_to :user
end
class PostedPhoto < Photo
has_many :handshakes, inverse_of: :poster, foreign_key: 'poster_id'
end
class SubmittedPhoto < Photo
has_many :handshakes, inverse_of: :submitter, foreign_key: 'submitter_id'
end
class Handshake < ActiveRecord::Base
belongs_to :submitter, class_name: 'SubmittedPhoto'
belongs_to :poster, class_name: 'PostedPhoto'
end
The STI part and associations between photos and handshakes work fine. The problem is getting all user's handshakes through his photos.
Using the code above Rails will obviously complain that model Photo does not have an association called handshakes. Is there any facility in AR that would allow me to specify a relation of this kind? If not, what query would you write to get them?
You could use in User:
has_many :submitted_handshakes, through: :submitted_photos, source: :handshakes
has_many :posted_handshakes, through: :posted_photos, source: :handshakes
I understand this works as is you had:
user.submitted_handshakes ----> user.submitted_photos.handshakes
Obviously handshakes method does not exist in submitted_photos, but AR made this for you by joining tables.
I ended up using the following code, looked like an easiest option to solve this problem.
class User
def handshakes
Handshake.where('submitter_id IN (?) OR poster_id IN (?)', submitted_photo_ids, posted_photo_ids)
end
end

Resources