Stephan,
> I have a has_and_belongs_to_many relationship, let's say
> class Student < ActiveRecord::Base
> has_and_belongs_to_many :courses
> end
> class Course < ActiveRecord::Base
> has_and_belongs_to_many :students
> end
CRUDify/complexify your models, and your life/code will be simpler:
add 1 model - Enrolment - and use has_many :through instead of hbtm
Something like (untested) :
class Student
has_many :enrolments , :dependent => :destroy
has_many :courses , :through => :enrolments
end
class Course
has_many :enrolments , :dependent => :destroy
has_many :studends , :through => :enrolments
end
class Enrolment
belongs_to :course
belongs_to :studen
end
You would then create enrolments explicitely
Enrolment.create(:student => a_student, :course => a_course)
(you'd place the validations rules in the enrolment model).
For more about this CRUDification, see slides 24 and following of
"World of resources", by DHH
http://media.rubyonrails.org/presentations/worldofresources.pdf
Alain Ravet
Stephan
> Thanks - sounds good. What would the controller's update method
> look like then?
By creating a new model - Enrolment - you simplify your controller by
having the model do all the - model - validation.
> Enrolment.create will manipulate the database, while I want to first
> perform validations (must have at least one 4-credit course, for
> example), before the database-saves.
Something like (untested) :
class Enrolment < ActiveRecord::Base
belongs_to :course
belongs_to :student
protected
def validate
errors.add("student", "does not have enough credits") unless
student.credits >= 4
end
end
API validations :
http://api.rubyonrails.com/classes/ActiveRecord/Validations.html#M000931
Alain Ravet
Stephan
My code was just an example; adapt for your needs.
> The first "Enrolment.create" might fail, even if the parameters
> submitted from the form contain a 4-credits course (unless the
> controller does some sorting, which doesn't look proper either).
I don't understand :
class Enrolment < ActiveRecord::Base
..
def validate
errors.add("student", "does not have enough credits") unless
student.credits >= 4
end
end
will only fail if student.credits < 4
In the controller you'd have something like
def register
student = Student.find(params[:student_id])
course = Course .find(params[:course_id])
if Enrolment.create(student, course)
..
else
flash[:notice] = "student cannot be enrolled for this course"
..
end
end
Alain Ravet
Stephan,
> In the form there are checkboxes for a whole bunch of courses.
> So there would be a whole sequence of
>
> Enrolment.create(student, course1) # course1 was checked off.
> Enrolment.create(student, course2) # course2 was checked off.
> Enrolment.create(student, course3) # course3 was checked off.
>
> But validation depends on the whole set (does one of them have 4
> credits).
I guess you have two options :
- check the form values in the controller before creating any new
record (the validation logic could be moved to the model, in a class
method.),
or
- add a more complex (multiple) creator in the model.
Alain Ravet