Rails model design for user specific result - ruby-on-rails

I currently have two Rails models as follows:
class Job < ApplicationRecord
has_many :job_interests
end
class JobInterest < ApplicationRecord
belongs_to :job
belongs_to :applicant
enum status: { pending: 0, accepted: 1, rejected: 2, cancelled: 3 }
end
I am trying to achieve that for a specific applicant (user) I can serve a list of Jobs. Each Job should be associated with one or zero JobInterest instances (for that specific user).
I've thought of multiple ways to achieve this, but all seem a bit cumbersome.
Possible solution 1:
Basically use a LEFT OUTER JOIN, e.g.
Job.includes(:job_interests).where(job_interests: { applicant_id: [current_applicant.id, nil] }).all
This results in a job list, each job having a property called job_interests which should have one item or none. One if the applicant has expressed interested, and none if the applicant hasn't done so.
Drawback: this doesn't seem like to the most straightforward approach.
Possible solution 2:
When a Job is created, automatically create JobInterests for all applicants belonging to this job. Given a lot of applications, this doesn't scale well and requires a lot of extra rows.
On the other hand, one can now get the Job list by calling
JobInterest.where(applicant_id: current_applicant.id).all
, which seems much cleaner than the previous approach.
Would you pick any of these approaches, or suggest another approach I haven't thought of.

So based on my comments in your question I think its just a simple has_many :through association. A User has many job interests and a Job has many interested Users.
class JobInterest < ApplicationRecord
belongs_to :user
belongs_to :Job
end
class User < ApplicationRecord
has_many :jobinterests, dependent: :destroy
has_many :jobs, :through => :jobinterests
end
class Job < ApplicationRecord
has_many :jobinterests, dependent: :destroy
has_many :users, :through => :jobinterests
end
This way you can simply add jobs to job interests when you view them, and remove them from the list when the user opts out of the job.

Related

Using where, then a relational association

This has come up again and again in the project I'm working on so am going to try and get an answer once and for all.
I'm trying to use where, and then collect all of an association. I can't describe the problem well so it may have been answered before (in fact, I'm sure it has) but here is an example.
I have applicant_approvals, which is a join table between a few different relations. It also has its own column, approved. I'm trying to get all applicant approvals where an applicant has been approved, and then get those applicants. So something like:
#stage.applicant_approvals
.where(approved: true)
.applicants
Now, of course, you can't do that because where returns an active record association. I don't want to use first because I want all the applicants that have been approved of that stage of the process.
Is there an acknowledged way to do this or do I need to get the association, then run it through an each to get each applicant?
thanks.
You can do this by setting up indirect associations:
class Applicant < ApplicationRecord
has_many :applicant_approvals
has_many :stages, through: :applicant_approvals
end
class ApplicantApproval < ApplicationRecord
belongs_to :applicant
belongs_to :stage
end
class Stage < ApplicationRecord
has_many :applicant_approvals
has_many :applicants, through: :applicant_approvals
end
Then just create pop a where clause onto the association:
#stage.applicants.where(applicant_approvals: { approved: true })

Using a junction table with its own relationship

I'm creating an app that has a User and a Plugin model. A user can have multiple plugins and a plugin can belong to multiple users, which I've implemented using a junction table.
class Plugin < ActiveRecord::Base
has_many :user_plugins
has_many :users, through: :user_plugins
end
class User < ActiveRecord::Base
has_many :user_plugins
has_many :plugins, through: :user_plugins
end
class UserPlugins < ActiveRecord::Base
belongs_to :user
belongs_to :plugin
end
However, I then want to store arbitrary data for each user plugin (for example, things like api keys, options etc that can differ for each plugin.).
My initial approach was to have a user_plugins_options that joined on user_plugins, but I can't seem to get this to work correctly.
class UserPluginOptions < ActiveRecord::Base
belongs_to :user_plugins
end
My question, how should I go about approaching this to best work with ActiveRecord?
I think you misnamed your class, as the table is user_plugins but the model is UserPlugin. It’s plausible you are running into issues because of this.
Agree with Alex. Why don’t you create a json field on UserPlugin called options and keep a hash of plugin specific values here.
If you must have another table, you should add a has_one :user_plugin_option to your UserPlugin

Layers of associations and descriptions on rails

I am trying to implement a resume feature and I was wondering the best practice for handling it. Lets assume a user has 2 pieces to a resume, education and work experience, and this is constant among all users. Then under each I want to save titles of things they've done (eg. Attended school at ______, worked at ________, project doing _______). Within these I want to save a description of that specific activity. What would be the best practice for implementing this?
So I need some association like: a user has_many experiences. An experience has_many titles. A title has_many descriptions. I also need to make the title of the experience is associated with the correct header (education or work experience).
I'm still pretty new to rails, and I'm sure there is a much easier and intuitive way to do this. Thanks for the help!
You can try these simple models structure for
class User < ActiveRecord::Base
has_many :locations
has_many :projects, through: experience_projects
end
class Location < ActiveRecord::Base
belongs_to :user
end
class Experience < ActiveRecord::Base
#experiences table should contain title and descriptions
belongs_to :user
has_many :projects, through: experience_projects
end
Now Join model if you do not require this intervention model you can directly use has_and_belongs_to_many
class ExperienceProject < ActiveRecord::Base
belongs_to :user
belongs_to :experience
end

ActiveRecord with two has many collection and a group_by query

I'm trying to query for the person's number of clicks per board.
so I can show a table of the people of that board. and for each to show the number of clicks he got.
How do I create an activeRecord query for this information?
My 3 models:
class Click < ActiveRecord::Base
belongs_to :board
belongs_to :person
end
class Board < ActiveRecord::Base
has_many :persons, dependent: :destroy
has_many :clicks, dependent: :destroy
end
class Person < ActiveRecord::Base
belongs_to :board
has_many :clicks, dependent: :destroy
end
Well, there are many ways to build your query for this, one of them is:
Click.where(person_id: your_person_id_variable, board_id: your_board_id_variable)
This way you have an array of clicks with the person, and board information. Also you have the array size, that represents the number of clicks.
You can use the board as the main model too, and use sql joins to bring the other data. It is basically the same approach:
Board.joins([:persons, :clicks]).where("persons.id = #{your_person_id_variable}
AND clicks.id = #{your_board_id_variable}")
You should take a look at the Rails Guides in this part of relationships and the ActiveRecord Query Interface. Also make extensive use of the Rails console, you can test anything there and make it easy to understand all of the concepts.

Advice on RoR database schema and associations

New to RoR, but am having a stab at building an app - and I'm looking for some advice on my db structure.
I've got 4 models/tables: Users > Clients > Jobs > Tasks
The app will work as follows:
Users will login
They can add Clients
They can add Jobs to Clients
They can add Tasks to Jobs
So, Tasks belong to Jobs, Jobs belong to Clients, and Clients belong to Users.
I want to query the DB for any one of a Client, a Job, or a Task and also make sure that it belongs to the currently logged-in User. I'm struggling to write a 'railsy' join query and design my associations so I can do this.
I know this would be super easy if I had a user_id field in every table, but that doesn't seem like the right way to do it.
I've read the guide at http://guides.rubyonrails.org/association_basics.html, but am still in the dark a little. Can anyone shed some light on how I might structure my DB - and more importantly my associations?
Thx.
It seems you have your associations set up right from one side, all you have to do is add the other end of the associations using has_many:
class Task < ActiveRecord::Base
belongs_to :job
end
class Job < ActiveRecord::Base
belongs_to :client
has_many :tasks
end
class Client < ActiveRecord::Base
belongs_to :user
has_many :jobs
has_many :tasks, :through => :jobs
end
class User < ActiveRecord::Base
has_many :clients
has_many :jobs, :through => :clients
has_many :tasks, :through => :jobs
end
Now ActiveRecord will take care of the joins for you. It's true that in a pure db schema, you should not have the user_id in more than one place(here that would the clients table). However sometimes it would be added also to the tasks and jobs table for a performance boost, because then the db queries would not be so big. Nevertheless you have to put more effort into making your data consistent - you have to ensure that a job has the same user_id as its client for example.
Then you would be able to define shortcut associations like:
class Task < ActiveRecord::Base
belongs_to :user
end
But in this case I would not do it unless you notice the queries are too slow for your needs. Premature optimization is evil :-)
I'm not sure, if I understood your question correctly, but I believe this can be a solution:
If you write your associations like this, ActiveRecord will create automatically the joins if you ask for user.jobs or user.tasks.
class User < ActiveRecord::Base
has_many :clients
has_many :jobs, :through => :clients
has_many :tasks, :through => :jobs
end
For more Information see the Rails-Api-Documentation
If you want to get everything for a user in one request. You can do this:
user.clients.joins(:jobs => :tasks)

Resources