I am setting up an application and I am having issues with ActiveRecord relationships. here is the breakdown.
1. A Client has_many Sites therefore a Site belongs_to Client
class Client
has_many :sites
end
class Site
belongs_to :client
end
2. A Site has_many Reports therefore a Report belongs_to Site
class Site
has_many: reports
end
class Report
belongs_to :site
end
this is where I am getting stumped.
A Patrol has_many Hits therefore a Hit belongs_to Patrol
A Hit belongs_to Site therefore a Site has_many Hits
a Report belongs_to Site therefore a Site has_many Reports
the problem is setting this last part up not too sure to to layout the models or if a :through relationship is warranted?? Essentially what I am hoping to achieve here is that when an admin sets up a patrol and assigns a site to a hit the user can view the site through the hit show page and generate a new site report than can then be viewed under the client/site show page in the admin table.?
Am I out in outer-space here??
Nesting the client and site was a breeze and i can generate a new report from the site show page, but to streamline report creation for the end user I am hoping to go the above route.. just not sure about how to proceed.
If you require further assistance please let me know ill give you what I can!
Thanks.
EDIT # 1 My Model Structure
This group is nested as a site is built through the client show page
class Client
has_many :sites
end
class Site
belongs_to :client
end
This is where I am having the most troubel, as there is alot going on
here at least in my mind. I am open to any suggestions in configuring
this..
class PatrolRoute
has_many :patrol_hits
end
class PatrolHit
belongs_to :patrol_route
# A PatrolHit Should only have one Site and that site should not be created only selected from a dropdown box of pre-existing sites
end
class Site
belongs_to :patrol_hit
has_many: patrol_reports
end
Class PatrolReport
belongs_to :site
has_many :line_items
end
class LineItem
belongs_to :report
end
It is hard to provide you with exact answer since the whole thing and DB structure are unclear.
One thing that might help you to deal with all those associations is simple:
belongs_to :foo means that model's DB table should have foo_id column.
In your particular case
class PatrolHit
belongs_to :patrol_route
end
means that patrol_hits table should have columns like
id
patrol_route_id
...
I think keeping that rule in mind would help you.
Related
I'm starting to code a linkedin-like website in Rails for my thesis that would enable members to post job offers (employers) and other members (employees) to respond to them.
I've been trying to wrap my head around the data model and associations - because I don't want to have two channels of authentication for emploYers and Yees - I want to keep email, nickname and password in one table (model) and use that for logging in, and then from there go to Employer and Employee specific data.
I was reading about STI but I figured that Yer has very different data than Yee and there would be a lot of nulls in the Users table, which isn't quite an optimal thing I suppose.
Then I've stumbled across polymorphic associations, but I don't really know how to set them up.
I was thinking of something like this:
User < ApplicationRecord
has_one :employer, polymorphic: true
has_one :employee, polymorphic: true
end
Employee < ApplicationRecord
end
Employer < ApplicationRecord
end
My head boils cause I don't know what's the best way to achieve this, any tips much appreciated,
cheers
You don't need to use the polymorphic association here.
User < ApplicationRecord
has_one :employer
has_one :employee
def employer?
employer.present?
end
def employee?
employee.present?
end
end
Not sure if this would be the best solution in your case though.
I'm the middle of creating a RoR application which needs a Many-to-many association between the same table (at least in theory).
How so? Well, I'd need a User table which contains two kind of users: Server, and client, more or less like the idea of a Teacher and a student (with private lessons, but with multiple teachers), or a Doctor and a Patient
My first idea was to simply make a User table (you know, login, email, and personal info) and assign it a Role (Server, or client), but then I thought that making such association with a third-table would troublesome
USER <-----> USER_USER
But the idea of creating two "login" tables that represent each role, and a third-table for the association sounds wrong.
Client_Login <-----thru---> Client_Server <---thru---> Server
For simplicity sake, a client cannot be a server to another clients, and a server cannot be a client for another server.
Obviously, a server can have multiple clients, and a client has multiple servers
How would recommend modeling this relationship?
If you need to explicitly have different methods between the two, Server and Client, which I am assuming since you want different classes. Then you might want to look into Single Table Inheritance(STI). This will allow you to use one User table, but have two different models that use it.
class User < ActiveRecord::Base
belongs_to :another_model #example association that will exist for all user types
self.inheritance_column = :role
# if you need to be able to tell what role are available
def self.roles
%w(Client Server)
end
end
class Client < User
has_many :server_clients
has_many :servers, through: :server_clients
end
class Server < User
has_many :server_clients
has_many :clients, through: :server_clients
end
You then have to just setup a simple server_client.rb model for the bridge.
example from here: http://samurails.com/tutorial/single-table-inheritance-with-rails-4-part-1/
This will allow you to put common functionality for all Users in the User class, and specific functionality in the respective classes of Server and Client.
It's done all the time. It's quite common to have a many-to-many back to yourself. It's common in hierarchies dealing with people's relations to each other, (dependency, managers, children, etc... )
class User
has_many :user_relations, dependent: destroy, inverse_of: :user
has_many :dependent_users, through: :user_relations
has_many :dependent_upon_users, through: user_relations, source:
:dependent_upon
end
class UserRelation < ActiveRecord::Base
belongs_to :user
belongs_to :dependent_upon, class_name: User
validates_presence_of :user, :dependent_upon
end
So I am setting up a system of pages and apps, and app content. Where a page has_many :app_instances, and app_instances has_many :app_contents.
I have models:
page, app, app_instance, app_content
In my models:
class Page < ActiveRecord::Base
has_many :app_instances
end
class App < ActiveRecord::Base
belongs_to :page
end
class AppInstance < ActiveRecord::Base
belongs_to :page
belongs_to :app
has_many :app_contents
end
class AppContent < ActiveRecord::Base
belongs_to :app_instance
belongs_to :app
end
I'd like to have one object, where all the contents are under the individual contents live under the app instance... but is there a way to do this?
I setup this in one of my controllers:
#page = Page.includes(:app_instances).find(params[:id])
I can successfully debug #page.app_instances, but soon as I say #page.app_instances.app_contents i get an error. I am guessing this is just because i am missing the include within the include, but not sure how i write that, or even if that is "good practice"
I know i could probably do:
has_many :app_contents, :through => :app_instances
but id rather have the object organized with the instance holding the contents (that makes sense, right?)... so i could loop through all the instances, and print out the contents of the instance
Does my DB architecture make sense? or am I going at this the wrong way
Joel
You can include nested using:
Page.includes(:app_instances=>[:app_contents])
But main reason you are getting an error is because, in #page.app_instances.app_contents
page.app_instances doesn't have any app_contents. You would be looking for an union of app_contents of all app_instances of #page
So it can be done via:
#page.app_instances.app_contents.each{|ai| (list || =[]) << ai.app_contents}
list.flatten!
OR
define page has many app_contents through app_instances relationship in your model.
The first case would run query for each app_instances , however with using includes as I mentioned earlier that would result in single query. The second case would result in a single join query joining app_contents, app_instances table
I have a 'tip' model and a 'team' model. I am trying to create a form where a user will select the winning teams from several games. So far the user can select the winning teams and those id's are being saved as foriegn keys in the Tip model (team_id). But after saving, I can't go (for example ) #tip.team.name . What do I need to do ? How do I associate it (I though rails might magically do it if foriegn key is set), I am very new to rails. Thanks for any help !
class Tip < ActiveRecord::Base
attr_accessible :user_id, :team_id, :team, :game_id, :game, :comp, :comp_id
belongs_to :game
belongs_to :comp
belongs_to :team
end
class Team < ActiveRecord::Base
attr_accessible :name
has_many :tips
end
def create
params['game'][0].each do |key, value|
#tip = Tip.new
#tip.team_id = value
#tip.game_id = key
#tip.save
end
This last method may be messy too, but not sure how else to do it. There are several 'tips' that I want to create in the one form.
EDIT : To be clear I am quite sure it's a one to many relationship, I am creating several tips in the one form but each tip only relates to one team.
EDIT : Actually my approach (which I'm sure is not close to the best way, did allow tip.team.name. It was a silly error relating to my test data that made me think otherwise.
What you really need is to use a has_many through relation to link the tips and the teams. This is because one tip can have many teams, but also one team can be on many tips. You will need to create a third table to do this, maybe named TeamsTips. Here is how you might set it up:
class Tip < ActiveRecord::Base
has_many :teams_tip
has_many :teams, :through => :teams_tip
end
class TeamsTip < ActiveRecord::Base
belongs_to: teams
belongs_to: tips
end
class Team < ActiveRecord::Base
has_many :teams_tip
has_many :tips, :through => :teams_tip
end
Now when you have a #tip, you can find all the teams for it with #tip.teams. Remember, this will be an array so to get the first team use #tip.teams[0]. Likewise, if you have an #team, you can get all the tips for it with #team.tips.
For more informations on how to setup this has_many through association, see A Guide to Active Record Associations
if ur asscociation is "Tip belongs to a Team " and "Team can have many Tips" then the association u defined in the question is correct.
if u want to created multiple tips when a team is created or add/edit/delete tips for a already created team, have a look at "accepts_nested_attributes_for" and https://github.com/ryanb/nested_form.
If u can get the team name using '#team.name' then u should get it using "#tip.team.name"
need some advice.
I'm doing a project on RoR, and do not sure what relationship between the models should I use. I've got three models - Users, Boards and Messages.
The beginning is pretty simple:
User has one Wall, and it belongs to the User, so I guess this should be:
class User < ActiveRecord::Base
has_one :board
end
class Board < ActiveRecord::Base
belongs_to :user
end
The last model is Messages and here comes my problem. Message belongs to User cause he writes it, but it also belongs to a Wall cause he writes it on a wall (and it can be Wall that belongs to other user).
I used the simple solution:
class Theme < ActiveRecord::Base
belongs_to :board
belongs_to :user
end
class User < ActiveRecord::Base
has_one :board
has_many :themes
end
class Board < ActiveRecord::Base
belongs_to :user
has_many :themes
end
But I not satisfy with it, and feel that it isn't perfect. I'm looking for a solution that will let me write thinks like:
user.themes.create(:board => #board)
(now it doesn't fill user_id field)
I hope that isn't a hard task for those who more experienced than me in Ruby on Rails model. I'll appreciate good advices, thanks.
For normal you use some authentification gem like devise. Then you have the current_user variable which includes the object of the user that is currently calling the action.
Then when a user creates the Topic you add one simple line to the controller to set the user:
#theme.user = current_user
You should also use a gem like cancan to manage the authorisation in a cenral file. Youl find a railscast here:
http://railscasts.com/episodes/192-authorization-with-cancan