3

I have a rails 4 app running devise 3.x and I am having trouble adding a :first_name column to my Player model. I have 2 separate models that inherit from a User model - Player and Coach

I followed this 12 spokes post but am having trouble rendering the registration form in development mode.

I have a class PlayerParameterSanitizer to override the devise signup action and add the :first_name parameter

class PlayerParameterSanitizer < Devise::ParameterSanitizer
  def sign_up
    default_params.permit(:type, :email, :password, :password_confirmation, :first_name)
  end
end

and I create a new object of this class in the application controller

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  protected

  def devise_parameter_sanitizer
    if resource_class == Player
      PlayerParameterSanitizer.new(Player,:player,params)
    elsif resource_class == Coach
      CoachParameterSanitizer.new(Coach,:coach,params)
    else
      super
    end    
  end

end

I'm loading the sanitizers in an initializer in config/initializers/sanitizers.rb

require "#{Rails.application.root}/lib/player_sanitizer.rb"

Yet, I'm still getting the

undefined method `first_name' for #<Player:0x00000101cafab0>

on the view/players/registrations/new.html.erb page. What am I missing here?

update

db schema

  create_table "players", force: true do |t|
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "first_name"
  end

Update #2

devise_for :players, :controllers => {:registrations => "players/registrations",
                                        :sessions => "players/sessions",
                                        :passwords => "players/passwords"}

models for unrelated sanity

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

end

Player class inheriting from User.

class Player < User

end

Update #3

I shouldn't be using STI in this fashion, I don't think.

I want Coach and Player to share Devise Auth Functionality but Player will have additional fields to Coach (club, position, year, etc.)

With STI for rails 4 all attributes would be stored on the User table. But this means a Coach would have those fields but be saved in it's table as having nil for stuff like position, current club, etc.

That seems incorrect..

Basically, I want both Coach and Player to inherit from User so as to achieve devise functionality. But, I want Player to have several fields in addition to that of Coach.

computer_smile
  • 2,117
  • 2
  • 24
  • 42
  • could it be more of a problem with how my models are set up? added a `:first_name` to the User model and no longer getting the noMethodError – computer_smile Jan 13 '14 at 02:05
  • Not entirely sure why this approach isn't working http://stackoverflow.com/questions/16297797/add-custom-field-column-to-devise-with-rails-4 could it be because I'm overidding the devise controller? Moving this logic to Players controller.. – computer_smile Jan 14 '14 at 05:05
  • Please See update number 3 – computer_smile Jan 15 '14 at 19:03

3 Answers3

2

You can use polymorphism as well and database attributes won't be shared. Something like the following:

class Login < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  belongs_to :user, polymorphic: true
end

class Player < ActiveRecord::Base
   has_one :login, as: :user
end


class Coach < ActiveRecord::Base
   has_one :login, as: :user
end

This is just to give you a rough idea. Notice that I haven't tried any of this and that probably special care is to be taken if you use a class not named User in Devise. Good luck!

deivid
  • 4,808
  • 2
  • 33
  • 38
1

You need to be sure your router is using the proper controllers too. Otherwise it will load the controllers from Devise (which is a Rails engine), try this in your router:

devise_for :users, :controllers => { registrations: 'users/registrations' }

Otherwise, I'd also take a look at this question: https://stackoverflow.com/a/19793371/103739

Community
  • 1
  • 1
JP Silvashy
  • 46,977
  • 48
  • 149
  • 227
  • I've updated my question with current `routes.rb` and also the models in question. Given the `NoMethodError` could it be that I'm overlooking something obvious about STI + Devise? Creating a new player in the console `player = User::Player.new` does not even yield a `:first_name` attribute reference. How can this be given the migrations ran correctly and the current schema? (I have tried recreating local db several times) – computer_smile Jan 15 '14 at 05:51
  • ok I understand the devise side of it but I think my question (initially unknowingly) is a question of STI related to this http://stackoverflow.com/questions/17480029/single-table-inheritance-in-rails-4 – computer_smile Jan 15 '14 at 06:46
0

It would seem after further research (http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html) that with STI all attributes should be added to the User table. This will result (in my case) in Coach having nil values for the additional fields Player will have.

This can lead to scaling problems later on and is not so related to strong params + Devise for rails 4 as I had initially thought.

computer_smile
  • 2,117
  • 2
  • 24
  • 42