Search code examples
ruby-on-railsruby-on-rails-4rails-activerecordhas-manybelongs-to

Rails belongs_to relationship if meets certain condition


I have a rails app in which students can apply to projects posted by employers. I have it so a Student has_many projects, and a Project belongs_to Student. The problem is that the project can exist for a long time before a student is chosen for it. What I mean by this is that until an employer presses the hire button in a view, the student_id of project is nil. Once the employer presses the 'hire' button, I am trying to set the student_id of project to the student who was hired. For some reason, I can't do this. Here is the Project model:

class Project < ActiveRecord::Base
      belongs_to :student
      belongs_to :employer
      has_many :relationships

    def change_it
        self.student_id = self.relationships.where(:state => :active).first.student_id
        self.relationships.each do |relationship|
          if relationship.state != :active
            relationship.deny_applicants
          end
        end
    end
end

When I click the hire button, it takes me to the next page as normal, but when i check the project's student_id in the console, it is still nil.

How do I fix this? Thanks.


Solution

  • I think that you want to introduce an additional model to capture the relationship between the Student and the Project. Maybe restating the problem will help clarify this.

    • A Professor can create a Project at any time
    • A Student can apply for a Project at any time after it has been posted
    • A Professor must approve a Student's assignment to a Project

    The first point suggests that the Project belongs to a Professor (not a Student). From the second and third points I would tend to say that a Student has an Assignment to the Project and that Assignment might have 'applied', 'approved', and 'declined' states. With that in mind I'd probably model it this way (with the state_machine gem):

    class Student < ARec
      has_many :assignments
      has_many :approved_assignments, class_name: 'Assignment', conditions: { state: 'approved' }
    end
    
    class Project < ARec
      has_many :assignments
      has_one  :approved_assignment, class_name: 'Assignment', conditions: { state: 'approved' }
    end
    
    class Assignment < ARec
      belongs_to :student
      belongs_to :project
    
      state_machine :state, initial: :applied do
        state: :approved
        state: :declined
    
        event :approve do
          transition all => :approved
        end
    
        event :decline do
          transition all => :declined
        end
      end
    end