1

For my website, I'm trying to find a way where if a user is logged in, then they can create a user for someone. For the website, I don't want just ANYONE signing up. Only a user can sign someone up for security reasons. I cannot figure out how to do that. I'm using devise for log in/sign up.

I'll post some of my code, but I'm not sure which ones I should post, still new to rails.

In here, I want the link to create a user/sign up. The sign up page should only be viewable if a user is logged in.

<!DOCTYPE html>
<html>
...
  <body>
    <div class = "auth">
      <% if !user_signed_in? %>
        <button class = "signed_in"><%= link_to "Login", new_user_session_path %></button>
    <% end %>

    <% if user_signed_in? %>
        <div class = "buttons">
          <button class = "button"><%= link_to("Logout", destroy_user_session_path, :method => :delete) %> </button>

        </div>
    <% end %>
    </div>
    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>

    <%= yield %>
  </body>
 </html>

I'll also post this. I think this is how the links work on the authentication.

<%- if controller_name != 'sessions' %>
  <%= link_to "Log in", new_session_path(resource_name) %><br />
<% end -%>

<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
  <%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end -%>

<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
  <%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
<% end -%>

<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
  <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
<% end -%>

<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
  <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
<% end -%>

<%- if devise_mapping.omniauthable? %>
  <%- resource_class.omniauth_providers.each do |provider| %>
    <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br />
  <% end -%>
<% end -%>

Here is where I guess how you sign up. I want this page only viewable if a user is logged in. The problem I see that I THNIK that a user can only get to the sign up page if he or she is logged out. I want the sign up page ONLY viewable if a user is logged in. Not sure how that will work.

<article class = "sign" >

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true %>
  </div>

  <div class="field">
    <%= f.label :password %>
    <% if @minimum_password_length %>
    <em>(<%= @minimum_password_length %> characters minimum)</em>
    <% end %><br />
     <%= f.password_field :password, autocomplete: "off" %>
  </div>

  <div class="field">
     <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "off" %>
  </div>

   <div class="actions">
    <%= f.submit "Sign up" %>
  </div>
<% end %>


<%= render "devise/shared/links" %>
</article>

I also posted the migration code, looks important

class DeviseCreateUsers < ActiveRecord::Migration[5.1]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, default: 0, null: false
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at


      t.timestamps null: false
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
    # add_index :users, :confirmation_token,   unique: true
    # add_index :users, :unlock_token,         unique: true
  end
end

Like I said, I am not exactly sure what code I should post for guidance. Let me know if I should post more to figure how to do this.

Also to note, I currently have no code in my user controller, maybe I will have to add stuff to make this work?

bockdavidson
  • 2,083
  • 3
  • 14
  • 21
  • This should somehow help you https://stackoverflow.com/questions/23140117/allow-a-user-to-add-new-users-in-devise-and-remain-logged-in-as-themselves – Pavan Jun 07 '17 at 16:33

1 Answers1

0

The same way you do it to check if the user is signed in and print the buttons, you can add a new link_to helper which points to a new route created to make this work:

# html.erb file (mostly application.html.erb)
<div class="auth">
  <% if !user_signed_in? %>
    <button class="signed_in">
      <%= link_to 'Login' new_user_session_path %>
    </button>
  <% else %>
    <div class="buttons">
      <button class="button">
        <%= link_to('Logout', destroy_user_session_path, method: :delete) %> 
      </button>
      <button class="button">
        <%= link_to 'Create a new account', new_account_path %><br />
      </button>
    </div>
  <% end %>
</div>  

You need to create a new controller which inherits from the Devise RegistrationsController, which will override the Devise new method, and will use the skip_before_action (Rails 5, for Rails 4 use skip_before_filter) callback in order to make it work with the overrided method:

# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
  skip_before_action :require_no_authentication, only: [:new]

  def new
    super
  end
end

Then in your routes you add the registrations_controller to make it work with Devise:

# config/routes.rb
devise_for :users, controllers: { registrations: 'registrations' }

And as a logged user define a GET route which match with the used in the link_to helper created in the first step:

# config/routes.rb
as :user do
  get '/new_account', to: 'registrations#new'
end

Here there's a repo to see how it works. Hope it helps.

Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
  • what would the command to create the new controller for registration? would it be rails generate controller Registration Devise:references? – bockdavidson Jun 07 '17 at 17:00
  • If you want a command then `rails generate controller Registrations` would create a new one, and also all the files related, or you can do it manually, being carefully in name and from which controller it inherits. – Sebastián Palma Jun 07 '17 at 17:03
  • Thanks! it worked! Also, is there a way where only certain users can create a new user based on their email address? – bockdavidson Jun 07 '17 at 17:22
  • You're welcome!, I think that would be a good new question in order to keep the questions tidy, because it implicates some validations and things so on. Feel free to ask again. – Sebastián Palma Jun 07 '17 at 17:26
  • I created the post https://stackoverflow.com/questions/44532781/rails-devise-and-authentication – bockdavidson Jun 14 '17 at 14:02