1

I have a User model which is designed after the Michael Hartl RoR tutorial and I am trying to create a new Teacher model. I would like the teacher to have many users but each user to have only one teacher. I created the teacher model with

class CreateTeachers < ActiveRecord::Migration
  def change
    create_table :teachers do |t|
      t.string :name
      t.string :email
      t.string :phone
      t.references :user, index: true, foreign_key: true

      t.timestamps null: false
    end
  end
end

and added has_one :teacher to user.rb. Here is the teachers.rb model

class Teacher < ActiveRecord::Base
  has_and_belongs_to_many :users
  validates :user_id, presence: true
  before_save   :downcase_email
  validates :name, presence: true, 
                 length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
  validates :email, presence:   true, 
                    length: { maximum: 255 },
                    format:     { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  private

    # Converts email to all lower-case.
    def downcase_email
      self.email = email.downcase
    end
end

However in my teacher_test.rb test file, things get a little fuzzy. I try this

def setup
  @user = users(:michael)
  @user2 = users(:archer)
  @user3 = users(:lana)
  @user4 = users(:mallory)

  @teacher = Teacher.new(name: "Phred Willard",
                         email: "pwillard@test.com",
                         phone: "1234567890",
                         user_id: [@user.id, 
                                   @user2.id,
                                   @user3.id,
                                   @user4.id])
end

test "should be valid" do
  assert @uac.valid?
end

but that fails outright. Did I set my relationship up correctly? I obviously am not adding users correctly since the model fails a validity test. How would I add more users to that teacher? Thanks in advance.

mjswartz
  • 715
  • 1
  • 6
  • 19

2 Answers2

1

Your teacher.rb should be

class Teacher < ActiveRecord::Base
  has_many :users
  before_save   :downcase_email
  validates :name, presence: true, 
             length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
  validates :email, presence:   true, 
                length: { maximum: 255 },
                format:     { with: VALID_EMAIL_REGEX },
                uniqueness: { case_sensitive: false }
  private

    # Converts email to all lower-case.
    def downcase_email
      self.email = email.downcase
    end
end

and user.rb

class User < ActiveRecord::Base
  belongs_to :teacher
  # rest of your code here ....
end

You need teacher_id column in users table.

archana
  • 1,282
  • 8
  • 11
  • I made these changes, but the validity test still fails. I think it's that I don't know how to add multiple users to a single teacher. Any help there? – mjswartz Jan 07 '16 at 01:32
  • Well, you are not creating users for a teacher in your unit test. What is `UnitAdvancementChair` in your test? – archana Jan 07 '16 at 01:45
  • Oops, copy and pasted from the wrong file. Updated the question with the correct code I tried. – mjswartz Jan 07 '16 at 02:19
1

I would like the teacher to have many users but each user to have only one teacher

You only need has_many / belongs_to...

#app/models/user.rb
class User < ActiveRecord::Base
   belongs_to :teacher
end

#app/models/teacher.rb
class Teacher < ActiveRecord::Base
   has_many :users
end

You'll need to add a teacher_id column in your users table (the opposite of what you have now):

class UpdateUsers < ActiveRecord::Migration
  def change
    change_table :users do |t|
      t.references :teacher, index: true, foreign_key: true #-> teacher_id
    end
  end
end

--

The error you have is that you're calling user_id on teacher; it should be teacher_id on user:

@teacher = Teacher.new(name: "Phred Willard",
                     email: "pwillard@test.com",
                     phone: "1234567890",
                     user_ids: [@user.id, 
                               @user2.id,
                               @user3.id,
                               @user4.id])

This should associate @teacher with the defined @users you've listed.

You'll also want to look at collection_singular_ids for the has_many association, which is why your test is failing.

Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • Awesome! Thank you (again). If I have a new user sign up and they want to select an existing teacher, how would I do that in the controller? I imagine something like `@teacher = Teacher.find(params[:teacher_id])` and then `@teacher.user_ids.add(params[:user_id])`, but I doubt that's correct. I'm not sure how to append to a list in Rails. – mjswartz Jan 08 '16 at 02:07
  • What about checking if a user has a teacher? Would it be accessed by `@user.teacher`? – mjswartz Jan 08 '16 at 22:51
  • You could use a validation in the `user` model (`validates :teacher, presence: true`) or you could just use something like `@user.has_teacher?` and define it in the model as `def has_teacher? teacher.present? end` – Richard Peck Jan 09 '16 at 09:35
  • I added the `has_teacher?` definition in the user model, but when testing it, I'm not getting the expected result. I tried testing with just `assert @user.has_teacher?` (`@user` comes from the setup seen in my original question), but that assertion fails. Any idea why? – mjswartz Jan 10 '16 at 23:07