edit link for "admins" in devise rails - ruby-on-rails

I have a rails app using devise for registrations and rolify for roles. I would like to have an index page that has edit links for each of the users that can be accessed by an admin. This edit page should also work without having to use a password. Right now the edit_user_path goes to the edit page of the current user, which is not what i want.
What is the best way to implement this sort of sitation? i've read a few of the posts on here about this but none seem to give me what i want.
Please point me in the right direction!
EDITED
I'm attempting to do it this way, still running into "Current password can't be blank"
From Users_controller:
def update
#user = User.find(params[:id])
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
if #user.update_attributes(user_params)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
And in my views i have an edit.html.erb file that is rendering the following form:
<div class="panel-body">
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
<%= devise_error_messages! %>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, class: "form-control", :autofocus => true %>
</div>
<div class="form-group">
<%= f.label :username %>
<%= f.text_field :username, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :firstname %>
<%= f.text_field :firstname, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :lastname %>
<%= f.text_field :lastname, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :city %>
<%= f.text_field :city, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :zip %>
<%= f.text_field :zip, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :state %>
<%= f.text_field :state, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :country %>
<%= f.text_field :country, class: "form-control" %>
</div>
<div class="form-group">
<%= f.submit "Update", class: "btn btn-primary" %>
</div>
<% end %>
</div>
and finally in my routes.rb file i have this line to render the edit page. I can get the edit page to show up but entering info and then hitting update just shoots me to /users with the error "Current Password can't be blank"
get 'pressroom/accounts/:id/edit' => 'users#edit', :as => :admin_edit_user

Devise doesn't come with any sort of Admin interface. If you are the only administrator and don't mind a little crudeness - there is always the console and/or scaffolding. You could create a UserController which inherits from ApplicationController and execute basic view, edit methods in the same controller. By placing the appropriate new.html.erb, edit.html.erb etc files in the User Views folder, adding/editing/deleting Users should work no differently as any other CRUD, as Devise's User is another model like any. Use a scaffold on the user and you could get what you are looking for.
There are also a lot of good gems that make setting up admin interfaces a cinch: https://github.com/gregbell/active_admin Active Admin, https://github.com/sferik/rails_admin Rails Admin and I'm sure there are a bunch more out there.

It looks like i got it working by adding:
<div class="panel-body">
<% #user = User.find(params[:id]) %>
<%= form_for(#user) do |f| %>
to the top of my _form.html.erb file
Thanks for the help everyone!

If the only thing you need is for the admin to EDIT an existing user, you can have the edit, show and update actions in a separate UsersController (and leave new and create actions up to devise). That way you can move that #user = User.find(params[:id] logic out of your form, into the controller, as #Saurabh Lodha mentioned.
I just thought one thing was missing from the answers though: Make sure to also edit your routes.rb. Use a path prefix so your routing doesn't get confusing, kind of like this:
devise_for :users, :path_prefix => 'my'
resources :users
this means that when you call edit on a current_user, it will go to my/users/edit, and when you call edit on any selected user from your user list in the admin panel, it will take you to users/user_id/edit.
I hope that clarified it a bit more! good luck! :)

Related

RoR: Forgot Password & Sign In - in same page

I'm trying to put Forgot password field with the sign in page, but if user is not registered (and not in apps database), then it redirects to the original devise Forgot password page with errors (http://localhost:3000/users/password). How do I make the errors appear in the same page as the sign in page (http://localhost:3000/users/sign_in)?
In app/views/devise/sessions/new.html.erb file
<%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<%= f.email_field :email, required: false, autofocus: true, placeholder: "Username" %>
<%= f.password_field :password, required: false, placeholder: "Password" %>
<%= f.button :submit, "Sign In", class: "btn btn-success btn-sm" %>
<div class="remember-forgot">
<div class="row">
<div class="col-md-6">
<%= f.input :remember_me, as: :boolean if devise_mapping.rememberable? %>
</div>
<div class="col-md-6 forgot-pass-content">
Forgot Password
</div>
</div>
</div>
<% end %>
<!-- where reset is -->
<div class="pass-reset">
<%= simple_form_for(resource, as: resource_name, url: password_path(resource_name), namespace: 'forgot', html: { method: :post }) do |f| %>
<%= f.error_notification %>
<label>Enter the email you signed up with</label>
<%= f.email_field :email, required: true, autofocus: true, placeholder: "Email" %>
<%= f.submit "Submit", class: "pass-reset-submit btn btn-success btn-sm" %>
<% end %>
</div>
So there's a javascript link where an input field will show up if a user forgets their sign in credentials.
apparently two forms for same object having same fields should not be one page, one should stay with the new page. but still i have tried your question, and following things needs to be done
1) I have to override the passwords controller for devise under user scope.
class Users::PasswordsController < Devise::PasswordsController
# GET /resource/password/new
def new
super
end
# POST /resource/password
def create
self.resource = resource_class.send_reset_password_instructions(resource_params)
if successfully_sent?(resource)
flash[:notice] = "sent password"
redirect_to :root
else
render "devise/sessions/new"
end
end
# GET /resource/password/edit?reset_password_token=abcdef
def edit
super
end
# PUT /resource/password
def update
super
end
protected
def after_resetting_password_path_for(resource)
super(resource)
end
# The path used after sending reset password instructions
def after_sending_reset_password_instructions_path_for(resource_name)
super(resource_name)
end
end
then my devise/sessions/new page will look like this(you can add the logic of showing form only when one clicks he forget password button. that should be simple. just add hide class and on click remove hide class.)
Log in
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<% if devise_mapping.rememberable? -%>
<div class="field">
<%= f.check_box :remember_me %>
<%= f.label :remember_me %>
</div>
<% end -%>
<div class="actions">
<%= f.submit "Log in" %>
</div>
<% end %>
#assuming that devise_mapping has recoverable? option. you can also keep the below form in if condition
<h2>Forgot your password?</h2>
<%= form_for(resource, as: resource_name, url: password_path(resource_name), namespace: "forget", html: { method: :post }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="actions">
<%= f.submit "Send me reset password instructions" %>
</div>
<% end %>
need to tell the routes to use my my passwords controller.
devise_for :users, controllers: {
passwords: 'users/passwords'
}
These things will result in showing the errors under the user sign in form but the path will remain http://localhost:3000/users/password. why because we are rendering the page and not redirecting. render just show the views without going to the controller action. now even if one tries to send the errors messages to the sessions controller somehow(after overriding that controller as well) somehow like this
redirect_to new_user_session_path, :messages => resource.errors
still that wont help, why because in session#new we are re initializing the resource as it is new action and all the errors would be gone.
I'm not sure if this is satisfactory to you or if this is not even close to your requirements. i tried to cover all things. i would be glad if some credible or official sources will provide even better response. that would definitely increase my knowledge as well.

Make the Devise new user form created with railapps a partial to re use it

I've created a new app with the Rails App composer with Devise and Pundit. The composer has created a form to create new users (devise/registrations/new.html.erb) which i would like to make a partial so i can put it on other pages. The form is
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :role => 'form'}) do |f| %>
<h3>Sign up</h3>
<%= devise_error_messages! %>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, :autofocus => true, required: true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
</div>ate_field :date_of_birth, class: 'form-control' %>
</div>
<%= f.submit 'Sign up', :class => 'button right' %>
<% end %>
if i put this into a partial and try to render it on another page i get
undefined local variable or method `resource
and that's obviously because in my controller i didn't define anything. Problem is i can't find the controller or what resource should be in the other controller so that i can re-use this.
The resource method you are looking for is located here
resource seems to be defined by an instance variable with the name of the actual resource you're using devise with.
So, if you use devise for the users resource you should define resource as User.new on the controller you want to render that partial, and mark it as helper_method so it may be used in views, or just define it straight in the helper.
Alternatively, you can just inherit DeviseController which already includes the resource definition and other useful methods as well.

Ruby on rails Landing Page

I have an extremelly basic rails 4 application. It's like a landing page with a video embeded from youtube and with a field for the user put his email and zipcode...
So, I am having trouble to save this user's email and zip code, actually, I am new at rails and I don't know how to do it... I have created a model called Information, with an email and zipcode(both strings)... I have a view called home with this code:
<%= form_for :information do |f| %>
<div class="form-group">
<%= f.label :Email_address %>
<%= f.text_field :email, class: "form-control", :autofocus => true, placeholder: "Enter email" %>
</div>
<div class="form-group">
<%= f.label :Zip_Code %>
<%= f.text_field :zipcode, class: "form-control", :autofocus => true, placeholder: "Zip Code" %>
</div>
<div class="form-group">
<%= f.submit "Submit", class: "btn btn-danger" %>
</div>
<% end %>
But when I click submit nothing happens, I think I should create a controller but I dont know what to put on it to make it work! What should I do to collect just this two information in the best way? Thanks very much!
You will need controller with two actions: :new and :create.
in console rails g controller informations (I assume your model called Information).
In this file
def new
#information = Information.new
end
def create
#information = Information.new(information_params)
redirect_to #information
end
private
def information_params
params.require(:information).permit(:email, :zipcode)
end
And then this code should go into /view/informations/new as new.erb
<%= form_for #information do |f| %>
<div class="form-group">
<%= f.label :Email_address %>
<%= f.text_field :email, class: "form-control", :autofocus => true, placeholder: "Enter email" %>
</div>
<div class="form-group">
<%= f.label :Zip_Code %>
<%= f.text_field :zipcode, class: "form-control", :autofocus => true, placeholder: "Zip Code" %>
</div>
<div class="form-group">
<%= f.submit "Submit", class: "btn btn-danger" %>
</div>
<% end %>
And take a look at some quick tutorial to have a basic understanding of how MVC established. This guide http://www.railstutorial.org/book is what almost everyone start.
Let me explain some things for you, as you're new
Objects
Ruby (& Rails by virtue of being built on Ruby) is object orientated. This means that every interaction you make with the Rails backend (the landing page doesn't interact with the backend initially), has to be centred around objects
Although you've done well by creating the respective objects (with the Information model), you need to appreciate the process of creating, populating & initializing the respecting objects
--
Form
You're using form_for requires an ActiveRecord object. This is your major downfall - say your landing page is at application#welcome, here's the
#app/controllers/application_controller.rb
Class ApplicationController < ActionController::Base
def welcome
#information = Information.new #-> creates "information" object
end
end
The form_for method can then take the #information object, to populate the data as required:
#app/views/application/welcome.html.erb
<%= form_for #information do |f| %>
<%= f.text_field :email %>
<%= f.text_field :zipcode %>
<%= f.submit %>
<% end %>
Notice how you're using the #information object here? This is where the ActiveRecord object comes in - allowing you to "populate" that as you wish
--
Backend
#config/routes.rb
root: "application#welcome"
resources :information, only: :create
The form_for will send your request to information_controller.rb:
#app/controllers/information_controller.rb
Class InformationController < ApplicationController
def create
#information = Information.new(information_params)
if #information.save
flash[:notice] = "Message Sent - Thank you!"
redirect_to "application#welcome"
end
end
private
def information_params
params.require(:information).permit(:email, :zipcode)
end
end
This will be able to take the #information object, populate it in the database, and then redirect to the original "landing" page again.

Can't make 'username' attr accessible in User model (Rails 4 - Devise)

I decided after creating a User model through Devise to add a column for a username. I realized that I'd need to make it accessible so that the database would update correctly when a user submits the new user form. I then realized that since this is Rails 4 I have to do that through the controller, and Devise doesn't make a controller for my User model available. So I followed the instructions at the Devise page and created my own custom controller and changed the route to use it. Here is my custom controller, which I placed in apps/controllers/users:
class Users::RegistrationsController < Devise::RegistrationsController
def new
super
end
def create
super
end
def edit
super
end
private
def user_params
params.require(:user).permit(:username, :email, :password, :password_confirmation)
end
end
I then modified routes.db with:
devise_for :users, :controllers => { :registrations => "users/registrations" }.
My form looks like this:
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => {:class => 'form-horizontal'}) do |f| %>
<%= devise_error_messages! %>
<div class="control-group">
<div class="control-label">
<%= f.label :username %>
</div>
<div class="controls">
<%= f.text_field :username %>
</div>
</div>
<div class="control-group">
<div class="control-label">
<%= f.label :email %>
</div>
<div class="controls">
<%= f.email_field :email, :autofocus => true %>
</div>
</div>
<div class="control-group">
<div class="control-label">
<%= f.label :password %>
</div>
<div class="controls">
<%= f.password_field :password %>
</div>
</div>
<div class="control-group">
<div class="control-label">
<%= f.label :password_confirmation %>
</div>
<div class="controls">
<%= f.password_field :password_confirmation %>
</div>
</div>
<div class="control-group">
<div class="controls">
<%= f.submit "Sign up" %>
</div>
</div>
<div class="control-group">
<div class="controls">
Already have an account? <%= render "devise/shared/links" %>
</div>
</div>
<% end %>
I copied the /devise/registrations' views to/users/registrations` per the instructions at the Devise page.
I'm not getting any errors but for whatever reason when I test the form it writes everything to the database except the username. I can go into the rails console and create users with usernames but it just won't happen with the form. My goal is to get the following line of code in application.html.erb to work:
Logged in as <%= current_user.username %>
But it never works and the failure is reflected in the console, which keeps showing the username as "nil."
Anyone know what I'm doing wrong? Where is the mistake?? I ran into a similar problem with my Post model with certain things not updating but I was able to fix it by changing which attributes were accessible in PostController. Thanks for any help!
Looking at the registration controller of devise, it looks like it is not using user_params. Try changing user_params to sign_up_params.

Saving information from nested forms in rails controllers

I'm trying to set up a simple Roles model for my site. Users can have any number of roles. Right now I'm setting it up to be a hidden field on the signup form. The problem I'm running into is that in my nested form the role type isn't being saved. An entry with the uid is being created in the roles table but that's about it. The relevant code is below. Any help would be appreciated.
== Schema Information
Table name: roles
id :integer not null, primary key
user_id :integer
role :string(255)
created_at :datetime not null
updated_at :datetime not null
Heres the create method from my users controller...
def create
#user = User.new(params[:user])
if #user.save
#role = #user.roles.new(user_id:#user.id, role:params[:role])
flash[:success] = "Thanks for singing up for the Auditions App, any audition invitations will be visible on this page"
#need to add the role guest to user roles
redirect_to #user
else
render 'new'
end
end
Heres the form....
<div class="span10 offset1 ajax-form">
<%= form_for(#user, :html => {:class => 'well'}) do |f| %>
<h3>Guest Account Signup</h3>
<%= render 'shared/error_messages' %>
<div class="pull-left form-field"><%= f.label :first_name %>
<%= f.text_field :first_name, :class => 'span4' %></div>
<div class="pull-left form-field"><%= f.label :last_name %>
<%= f.text_field :last_name, :class => 'span4' %></div>
<div class="pull-left form-field"><%= f.label :email %>
<%= f.text_field :email, :class => 'span4' %></div>
<div class="pull-left form-field span4"></div>
<div class='clear'></div><!--close .clear-->
<div class="pull-left form-field"><%= f.label :password %>
<%= f.password_field :password, :class => 'span4' %></div>
<div class="pull-left form-field"><%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation, :class => 'span4' %></div>
<div class="form_row pull-left form-field">
</div>
<%= f.hidden_field :role, :value => 'guest' %>
<%= f.submit "Create my account", :class => "btn btn-large btn-primary pull-left form-field" %>
<div class='clear'></div><!--close .clear-->
<% end %>
As #Arpit comments - get rid of the hidden :user_id tag. It's only confounding the attribute setter.
And I don't think building multiple roles using roles.new() (is that the same as roles.build()?) is going to cut it. You'll need to break out the separate roles' parameters and add them one at a time. Or you can grab them in one go like this:
selected_roles = Role.find_all_by_id(params[:roles])
#user.roles = selected_roles
This would assume that you are using role ids in your form, but you aren't for some reason...

Resources