i'm new in rails so i tried to do this to add a role, making a form to update and if the user update succsessfully add the role.
note: i'm using devise and rolify with cancancan
routes
get 'users/becomepartner' => 'users#becomepartner' do
collection do
patch 'update_partner'
end
end
and this is my users controller
def becomepartner
#user = current_user
end
def update_partner
#user = User.find(current_user.id)
if #user.update_with_password(partner_params)
self.add_role(:partner)
# Sign in the user by passing validation in case their password changed
bypass_sign_in(#user)
redirect_to root_path, notice: 'now you can create'
else
render :becomepartner
end
end
private
def partner_params
# NOTE: Using `strong_parameters` gem
params.require(:user).permit(:name, :style, :current_password, :email)
end
and this is my view becomepartner.html
<div>
<%= form_for(#user, :url => { :action => "update_partner" } ) do |f| %>
<div class="field">
<%= f.label :style %>
<%= f.text_field :style %>
</div>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %>
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i>
<%= f.password_field :current_password, autocomplete: "off" %>
</div>
<% end %>
</div>
In form action you have mentioned action as partner_update but you don't have that action. Change it to update_partner.
You are using the collection route for another individual route, that is get 'users/becomepartner'. So this will generate the collection route with url like:
users/becomepartner/update_partner
You can confirm this by running rake routes.
But your forms action url will be different.
What you can do is create this collection route inside users resource route like:
resources :users do
collection do
patch 'update_partner'
end
end
Then in form_for url option, use update_partner_users_path
If you don't want the users resources routes, then just define a single route like:
get 'users/becomepartner' => 'users#becomepartner'
patch 'user/update_partner' => 'users#update_partner'
I have not ran any of this code, so if there is any syntax error then post it in comment.
In routes.rb,change
patch 'update_partner' to update 'update_partner' and remove collection as you are not operating on a collection.you have added it in a do block,instead add a one liner route path.
in the form,url must be update_partner and NOT partner_update .
Related
In the below case, i am trying to use strong parameters. I want to require email_address, password and permit remember_me fields.
But using like below it only allows the LAST line in the method Ex:- In below case it only take params.permit(:remember_me)
private
def registration_params
params.require(:email_address)
params.require(:password)
params.permit(:remember_me)
end
Another Ex:- In this below case, if i rearrange it like below it will take only params.require(:email_address) where am i going wrong ?
def registration_params
params.require(:password)
params.permit(:remember_me)
params.require(:email_address)
end
UPDATE
Params hash be like
{
"utf8" => "ā",
"email_address" => "test1#gmail.com",
"password" => "password123",
"remember_me" => "true",
"commit" => "Log in",
"controller" => "registration",
"action" => "sign_in"
}
Ok found the answer through a friend ...one way to do this is
params.require(:email_address)
params.require(:password)
params.permit(
:email_address,
:password,
:remember_me
)
Works good.
Stong parameters are to prevent mass-assignment to Active Record models. Your parameters should be set up in a model backed form. Example from the Michael Hartl Tutorial:
REGISTRATION FORM
<%= form_for(#user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
This will create a parameter that looks like:
PARAMS
{
"utf8" => "ā",
"user" => { email: "test1#gmail.com", name:"Test Name", password: "password", password_confirmation: "password" },
"remember_me" => "true",
"commit" => "Log in",
"controller" => "registration",
"action" => "sign_in"
}
Then in your registration controller you can use strong parameters like:
STRONG PARAMETERS
params.require(:user).permit(:name, :email, :password, :password_confirmation)
It looks like in your case, you are handling a log in, in which case, you only need to use regular parameters to capture the login information.
SESSION CREATION
def sign_in
email = params[:email]
password = params[:password]
if User.authenticate!(email, password)
# do something
else
# do something different
end
end
Edit:
Here is the Rails way for you to handle logins and, I believe, cases where you need to 'require' multiple parameters and provide errors back to the user.
Unlike using strong params, this approach provides feedback to the user (using validation errors) when parameters are missing or blank. This is more user-friendly than throwing an exception.
Create an ActiveModel (not ActiveRecord) form backing object. This form backing object is where you specify which fields are required and when a call to valid? is performed, these fields will be validated.
With this, you will get nice user-friendly errors if:
email is missing
password is missing
email and password do not match
models/session.rb
class Session
include ActiveModel::Model
attr_accessor :password, :email, :remember_me
validates_presence_of :password, :email # these fields are required!
def authenticate
return false unless valid? # this checks that required params
# are present and adds errors to the
# errors object if not
if User.authenticate(:password, :email) # validate credentials
true
else
errors.add(:email, "and password didn't match") # wrong credentials. add error!
false
end
end
end
Create the controller. Here is what your controller would look like for logging in a user:
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
# GET /login
def new
#session = Session.new
end
# POST /login
def create
#session = Session.new(login_params)
if #session.authenticate
# do whatever you need to do to log the user in
# set remember_me cookie, etc.
redirect_to '/success', notice: 'You are logged in'
else
render :new # shows the form again, filled-in and with errors
end
end
private
def login_params
params.require(:session).permit(:email, :password, :remember_me)
end
end
Set up the view
app/views/sessions/new.html.erb
<% if #session.errors.any? %>
<ul>
<% #session.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<%= form_for #session, :url => login_path do |f| %>
<div>
<%= f.label :email, 'Email:' %>
</div>
<div>
<%= f.text_field :email %>
</div>
<div>
<%= f.label :password, 'Password:' %>
</div>
<div>
<%= f.password_field :password %>
</div>
<div>
<%= f.label :remember_me, 'Remember Me?' %>
<%= f.check_box :remember_me %>
</div>
<div>
<%= f.submit %>
</div>
<% end %>
Lastly, make sure the routes are configured
config/routes.rb
get 'login' => 'sessions#new'
post 'login' => 'sessions#create'
2020 solution:
def registration_params
params.require([:email_address, :password]) #require all of these
params.permit(:email_address, :password, :remember_me) #return hash
end
I'm using Rails 3.2 and Ruby 4. When I browse to http://localhost:3000/account/new I get an error:
NoMethodError in Accounts#new
Showing D:/row/dev/basic/app/views/accounts/_form_account.html.erb where line #1 raised:
undefined method `accounts_path' for #<#<Class:0x42c8040>:0x6daa960>
Extracted source (around line #1):
1: <%= form_for(#account) do |f| %>
2:
3: <div>
4: <%= f.label :username %><br>
I created Account views using rails generate controller Controllernames index show new edit delete. I also ran rails generate model account.
According to the online Rails course I'm following this should create in routes.rb:
Edit: I used rails generate model accounts, so with the s at the end.
resources :accounts
get 'accounts/:id/delete' => 'accounts#delete', :as => :accounts_delete
However, this was not created in routes.rb. My routes.rb after some editing is:
Basismysql::Application.routes.draw do
# Public pages
get '/page1' => 'pages#page1'
get '/page2' => 'pages#page2'
get '/page3' => 'pages#page3'
get "/account/index" => 'accounts#index'
get "/account/show" => 'accounts#show'
get "/account/new" => 'accounts#new'
get "/account/edit" => 'accounts#edit'
get "/account/delete" => 'accounts#delete'
get 'account/:id/delete' => 'accounts#delete', :as => :accounts_delete
devise_for :users
root :to => 'pages#index'
end
New.html.erb is:
<div class="container">
<h1>Accounts#new</h1>
<p>Find me in app/views/accounts/new.html.erb</p>
</div>
<div class="container">
<%= render "form_account" %>
</div>
And _form_account.html.erb is:
<%= form_for(#account) do |f| %>
<div>
<%= f.label :username %><br>
<%= f.text_field :username %>
</div>
<div>
<%= f.label :firstname %><br>
<%= f.text_field :firstname %>
</div>
<div>
<%= f.label :lastname %><br>
<%= f.text_field :lastname %>
</div>
<div>
<%= f.label :organisation %>
<%= f.text_field :organisation %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Part of the account controller is:
def new
#account = Account.new
end
def create
#account = Account.new(account_params)
if #account.save
redirect_to(:action => 'index')
else
render('new')
end
end
private
def account_params
params.require(:account).permit(:username, :firstname, :lastname, :organisation)
end
get "/account/index" => 'accounts#index'
get "/account/show" => 'accounts#show'
get "/account/new" => 'accounts#new'
get "/account/edit" => 'accounts#edit'
get "/account/delete" => 'accounts#delete'
get 'account/:id/delete' => 'accounts#delete', :as => :accounts_delete
This isn't the way you should create routes, they are all unnamed(besides the last one), non-restful and all are get, replace this with
resources :accounts
And your error will gone
This works
rails generate controller accounts index show new edit destroy
Note: you must use accounts and not account while generating the controller
rails generate model account
Note: you must have account as singular
in routes.rb
map.resources :accounts /or
resources :accounts
depending upon the version of rails
In addition to:
resources :accounts
you probably need:
resource :account
You've started it by adding the routes piece-meal to the routes file, but some of those need to be PUTs or POSTs or DELETEs. resource :account is a simpler shortcut to do it (correctly).
Im writing a game on rails, and am trying to allow a user to create their mine (its a mining game).
I have a table for the users, and a table for mines.
Each user has a ref. ID on their entry, pointing to their mine's ID in the mine table.
I'm getting an error when I try to visit /users/1/mines/new.
undefined method `mines_path'
I can't figure out why.
form in New:
<%= form_for [#mine] do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br>
<p>Depth: <%= #mine.depth %></p>
<%= f.submit "Submit", id: "submit" %>
<% end %>
Controller:
def new
#user = User.find(params[:user_id])
#mine = #user.mines.new
end
def create
#mine = #user.mines.create(mine_params)
if #mine.save
redirect_to users_mines_path
else
render new_mines_path
end
end
routes:
root 'welcome#index'
resources :sessions, only: [:create]
resources :users do
resources :mines
end
resources :tools, only: [:create]
How can I create a new mine THROUGH the user? Am I doing this correctly in my controller?
Thanks!
In your routes you have mines nested inside users so you need to change your form to something like this:
<%= form_for [#user,#mine] do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br>
<p>Depth: <%= #mine.depth %></p>
<%= f.submit "Submit", id: "submit" %>
<% end %>
OR
You can specify url option with your path:
<%= form_for #mine, url: user_mines_path(#user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br>
<p>Depth: <%= #mine.depth %></p>
<%= f.submit "Submit", id: "submit" %>
<% end %>
For details on forms refer to Form Helpers
Also as #Vimsha pointed out in your controller you need to use .new instead of .create as create will initialize and save your your mine.
def create
#mine = #user.mines.new(mine_params)
if #mine.save
redirect_to user_mines_path
else
render new_user_mine_path
end
end
#user.mines.create will create the mine. So use #user.mines.new
named route for mine index will be user_mines_path
named route for mine show will be user_mine_path(#mine)
named route for new mine will be new_user_mine_path
Contoller:
def create
#mine = #user.mines.new(mine_params)
if #mine.save
redirect_to user_mines_path
else
render new_user_mine_path
end
end
There is a lot of discussion around Rails 3 STI and how to use forms, but no definitive answers on StackOverflow. I seem to have run into a similar issue and have attempted the other solutions with no results.
I have two models with the following inheritance set up:
User.rb
class User < ActiveRecord::Base
attr_accessible :email, :first_name, :last_name, #more follows
Waiter.rb
class Waiter < User
On the form at /waiters/users/[:id]/edit, I am attempting to create a form for editing the waiter. However, I am getting the following error upon loading the edit view:
undefined method `waiter_path' for #<#<Class:0x007fbd08cef9d8>:0x007fbd09532fa0>
This is my controller found at /app/controllers/admin/waiters/users_controller.rb:
def edit
form_info
#user = Waiter.find(params[:id])
end
def update
#user = Waiter.find_by_id(params[:id])
if #user.update_attributes(params[:user])
flash[:notice] = "Successfully assigned Waiter."
redirect_to admin_waiters_users_url()
else
form_info
render :action => 'edit'
end
end
And this is the form located in the edit view:
<%= simple_form_for #user do |f| %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<%= f.input :email %>
<%= button_tag(type: 'submit', class: "btn btn-primary") do %>
<i class="icon-ok icon-white"></i> Save
<% end %>
<% end %>
What am I doing wrong here with STI and routing?
UPDATE: here is my rake routes:
admin_waiters_users GET /admin/waiters/users(.:format) admin/waiters/users#index
POST /admin/waiters/users(.:format) admin/waiters/users#create
new_admin_waiters_user GET /admin/waiters/users/new(.:format) admin/waiters/users#new
edit_admin_waiters_user GET /admin/waiters/users/:id/edit(.:format) admin/waiters/users#edit
admin_waiters_user GET /admin/waiters/users/:id(.:format) admin/waiters/users#show
PUT /admin/waiters/users/:id(.:format) admin/waiters/users#update
You should use your routes to see what routes you have defined:
You can run your routes with:
rake routes
I can not see your routes but perhaps waiter_path does not exist.
Perhaps is user_waiter_path(#user) or other router.
Please paste your routes for that the people on stackoverflow can help to you.
I can not see the route waiter_path on your routes, If you have waiter_path inside of your edit view you have remove it.
Also, you can specify what controller and action hit,
<%= simple_form_for #user, :url => { :controller => "admin/waiters/users", :action => "update"} do |f| %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<%= f.input :email %>
<%= f.button :submit, "save", class: "btn btn-primary"%>
<% end %>
You can check with f.button instead button_tag
Regards!
Devise gem is used for authentication. I need to have a user index and show view. Found this how to at the devise wiki, however played around, can not make it work.
Devise - How To: Manage users through a CRUD interface
Method 1: Remember to remove the :registerable module from the Devise model (in my case it was the User model) Make sure to put your map.resources :users below the map.devise_for :users route (devise_for :users and resources :users for Rails 3).
Method 2: devise_for :users, :path_prefix => ādā resources :users to isolate the devise logic from your crud user controlle
My question:
1. if you remove registerable in the model, then how does devise work for user?
2. If you done this, can you provide a sample?
Thanks in advance
The following worked for me.
users_controller.rb
class UsersController < ApplicationController
...
def create
#user = User.new(params[:user])
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
respond_to do |format|
if #user.save
format.html { redirect_to users_path, notice: 'User was successfully created.' }
else
format.html { render action: "new" }
end
end
end
...
end
routes.rb
...
devise_for :users, :path_prefix => 'd'
resources :users
...
I hope this can help you.
Regards,
Giacomo
By placing the appropriate new.html.erb, edit.html.erb, _form.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. I won't post the new or edit erbs (simple enough, and a scaffold can show you the rest), but an example of my User _form.html.erb...
<%= form_for(#user) do |f| %>
<%= render :partial => 'shared/errors', :locals => { :content => #user } %>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</div>
<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In mine, I think I left :registerable in and I'm still able to administer and update users via the CRUD. If you leave it out, then users can't register themselves, but you can still add and edit users yourself (would protect the Users controller with load_and_authorize_resource to keep regular users out, of course).