I have a Job
model that belongs_to
three users (customer, employee, and qa). The customer is set to current_user
when the job is created, but the employee and qa users pick their jobs from the pool of u开发者_Go百科nclaimed jobs.
The way I have this implemented currently is as follows: match 'jobs/:id/assign/:type/:user_id' => 'jobs#assign'
with an assign
method with a case statement on params[:type]
. So, for example, jobs/1/assign/qa/1
assigns user 1 as the qa for job 1.
This works, but it seems sloppy and I'd like to replace it with something cleaner. Is there a common convention for situations like this?
Edit: Users can have both employee and qa roles simultaneously. That's what's making me feel forcing into such a complex route.
class User < ActiveRecord::Base
has_many :submitted_jobs, :class_name => 'Job', :foreign_key => 'customer_id'
has_many :assigned_jobs, :class_name => 'Job', :foreign_key => 'employee_id'
has_many :reviewed_jobs, :class_name => 'Job', :foreign_key => 'qa_id'
class Job < ActiveRecord::Base
belongs_to :customer, :class_name => 'User', :foreign_key => 'customer_id'
belongs_to :employee, :class_name => 'User', :foreign_key => 'employee_id'
belongs_to :qa, :class_name => 'User', :foreign_key => 'qa_id'
You might consider a more RESTful approach to your problem. Two of the things RESTful Best Practices cites as "classic beginner's mistakes" is to "strongly mirror your ActiveRecord data model to choose your resources" and to "add custom methods if the standard ones don't fit."
Nouns are the new verbs
- Change your way of explaining the scenario, an action
- Use a noun to describe the action
- The noun given to your scenario is the resource you're looking for
- A user subscribes to a group -> A subscription is created
- The project is validated by its owner -> A project validation is created
- The user deactivates his account -> A user account activation is deleted
You could easily create a "Job Assignment" resource (not necessarily a separate model) and, for example, create
one with the right parameters. In rough pseudo-Rails:
# routes
resources :job_assignments, :only => [:create, :delete] # or whatever you need
# job_assignments_controller
class JobAssignmentsController < ApplicationController
def create
user = User.find(params[:user_id])
job = Job.find(params[:job_id])
user.assign(job, params[:job_type]) # handle model logic
end
def destroy
user = User.find(params[:user_id])
job = Job.find(params[:job_id])
user.unassign(job, params[:job_type]) # handle model logic
end
end
There are some good examples in the presentation (starting on slide 32).
I think a great way about solving this is design your routes first which is what you're doing.
Your current routing is great if the "Job" and the assignee are well known in advance. In my opinion if you stuff the the job AND the assignee type information in the route you're doing too much.
Do the employees/qa also login and pick their own jobs? If they do, then their own information will be available on the server side in "current_user".
In that case, the route should ideally be "/job/:id/pick" going to "JobsController#pick" action with a POST request for example. In your controller action you would get the eemployee/qa user info in the current_user.
config/routes.rb
resource :jobs do
member do
post :pick
end
end
in app/controller/jobs_controller.rb
def pick
job = Job.find(params[:id])
current_user.jobs << job # User has_many :jobs
# or
job.user = current_user
...
end
Please do let me know if employees/qa do NOT login and i'll update solution accordingly with another solution.
精彩评论