2

I have a Rails 4 app using Devise for authentication — and it is currently working.

I am now following this coderwall tutorial about Creating a Scoped Invitation System for Rails.

In the Newly Invited user registration section, the author recommends to udpate the RegistrationsController, as follows:

def new
   @token = params[:invite_token] #<-- pulls the value from the url query string
end

def create
  @newUser = build_user(user_params)
  @newUser.save
  @token = params[:invite_token]
  if @token != nil
     org =  Invite.find_by_token(@token).user_group #find the user group attached to the invite
     @newUser.user_groups.push(org) #add this user to the new user group as a member
  else
    # do normal registration things #
  end
end

There are plenty of questions and answers, on Stack Overflow as well as accross the web, explaining how to override Devise RegistrationsControllers, including:

So, I understand that creating a MyDevise::RegistrationController that would inherit from Devise::RegistrationsController and calling the super command at the beginning of the actions I want to modify will keep the original functions of these actions.

I could probably do something like:

def new
  super
  @token = params[:invite_token] #<-- pulls the value from the url query string
end

def create
  @newUser = build_user(user_params)
  @newUser.save
  @token = params[:invite_token]
  if @token != nil
    org =  Invite.find_by_token(@token).user_group #find the user group attached to the invite
    @newUser.user_groups.push(org) #add this user to the new user group as a member
  else
    super
  end
end

My only concern is that I am not comfortable overriding a controller and its actions without knowing the original content of this controller and those actions.

—————

UPDATE: I know we can access the Devise::RegistrationsController from Devise GitHub repository, but I am not sure mine is still the same. It could for instance have been modified when I implemented my authentication system.

—————

UPDATE 2: if I use the code from Devise::RegistrationsController mention in my first update, I can come up with the following code for my new RegistrationsController:

def new
  @token = params[:invite_token] #<-- pulls the value from the url query string
  build_resource({})
  set_minimum_password_length
  yield resource if block_given?
  respond_with self.resource
end

def create
  build_resource(sign_up_params)
  resource.save
  @token = params[:invite_token]
  if @token != nil
     org =  Invite.find_by_token(@token).calendar #find the calendar attached to the invite
     resource.calendars.push(org) #add this user to the new calendar as a member
  else
    yield resource if block_given?
    if resource.persisted?
      if resource.active_for_authentication?
        set_flash_message :notice, :signed_up if is_flashing_format?
        sign_up(resource_name, resource)
        respond_with resource, location: after_sign_up_path_for(resource)
      else
        set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
        expire_data_after_sign_in!
        respond_with resource, location: after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource
      set_minimum_password_length
      respond_with resource
    end
  end
end

Does that make sense at all?

—————

So, is there a way to pull out the content of my current Devise::RegistrationsController from somewhere in the app?

If not, does the code I am considering implementing make sense?

Community
  • 1
  • 1
Thibaud Clement
  • 6,607
  • 10
  • 50
  • 103

2 Answers2

4

You may use:

bundle open devise # bundle will open devise folder in your editor

About your code:

There's a cleaner solution. Take a look at this code:

def new
  build_resource({})
  set_minimum_password_length
  yield resource if block_given?
  respond_with self.resource
end

It's almost natural English, only yield resource if block_given? line may confuse you. This line does the following: if method new is called with a block, then pass resource variable to that block and execute it. This is done especially to ease adding of custom behavior and overwriting.

So, we can overwrite this code as following:

def new
  # here you don't need this `resource` variable, but somebody may need it
  super do |resource| 
    @token = params[:invite_token]
  end
end

which is absolutely the same as if you'd write

def new
  build_resource({})
  set_minimum_password_length
  @token = params[:invite_token]
  respond_with self.resource
end

EDIT 2: Try this:

def create
  super do |resource|
    @token = params[:invite_token]
    if @token != nil
      org = Invite.find_by_token(@token).calendar #find the calendar attached to the invite
      resource.calendars.push(org) #add this user to the new calendar as a member
    end
  end
end        
Alexey Shein
  • 7,342
  • 1
  • 25
  • 38
  • Thanks. I got `To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR` so I ran `export EDITOR='subl -w' ` and now when I try again to run `bundle open devise` I get `Could not run 'subl /Users/TXC/.rvm/gems/ruby-2.2.1/gems/devise-3.5.2' ` Any idea how to make this work? – Thibaud Clement Sep 15 '15 at 21:43
  • Awesome, thanks a lot for the code of the `new` action. Would you happen to have any suggestion for the code of `create` action, by any chance? – Thibaud Clement Sep 15 '15 at 21:52
  • 1
    This is strange, Sublime works fine for me. Does it open current folder with `subl .`? If not, does it open any file at all from command line? – Alexey Shein Sep 15 '15 at 21:55
  • 1
    `create` action is similar. You're writing `super do |resource| end` in your overwritten `create` action and imagine that your code is inserted instead of the line `yield resource if block_given?` in `Devise::RegistrationsController#create`. – Alexey Shein Sep 15 '15 at 21:57
  • Even if I have a condition to test BEFORE I run the original code? I mean, in the `new` action, I understand what you mean, since we pass `@token = params[:invite_token]` inside the original `new` action. However, in the case of the `create` action, we need to test `if @token != nil` and if `false` then we run the original `create` action code. Does that question make sense? – Thibaud Clement Sep 15 '15 at 22:02
  • You were correct Sublime Text, it was not setup correctly. Thanks for this tip! I could open Devise, thanks. – Thibaud Clement Sep 15 '15 at 22:04
  • I put that `else` here because this is the code to implement from the tutorial: https://coderwall.com/p/rqjjca/creating-a-scoped-invitation-system-for-rails (Look for the "Newly Invited user registration" section). – Thibaud Clement Sep 15 '15 at 22:09
  • 1
    I think it's just lazy programming. There's nothing in that code that would require to skip original devise code, but this way user won't be signed up for example. – Alexey Shein Sep 15 '15 at 22:17
  • Yes, you are correct. If I want to signup the user, I have to remove the else statement. This way, if there is a token, then the user is added to the calendar and he is signed up, otherwise, it is just regular signup. – Thibaud Clement Sep 16 '15 at 01:42
0

If you want to see what version of Devise you are using run this command in terminal: gem which devise. So that you will be able to check the proper source code on their GitHub based on the version you are using.

Antoine
  • 559
  • 8
  • 21
  • Thanks for your comment. I am actually not try to see what version of Devise I am using (I know that). What I want is to access the current code of my Devise RegistrationsCtronoller to see how I can implement the changes I need to make. – Thibaud Clement Sep 15 '15 at 21:45
  • I think you just got your answer above :-) – Antoine Sep 15 '15 at 21:47