I am very new to rails and am attempting to get some practice by building a profile page. I have implemented devise and once a user has signed in they can click on a link that displays a profile with information about them. Right now it is just displaying their name, date of birth, and gender. I would like for it to also display an image of them. So I have bundled the paperclip gem and read through some tutorials to try and get it configured. I have gotten the code in place, so that a user can click on 'choose file' and select an image. However when I click 'update' it provides me with an error. I'd like for the image to display on the same show page of their profile.
profiles_controller.rb
class Users::ProfilesController < ApplicationController
def edit
#profile = Profile.create(params[:photo])
end
def create
end
private
def profile_params
params.require(:profile).permit(:photo)
end
end
profiles/edit.html.erb
<h2>Edit Account Profile </h2>
<%= form_for(#profile, url: profiles_edit_path(#profile), html: { :multipart => true }) do |f| %>
<li>
<%= f.label :photo, "Photo" %>
<%= f.file_field :photo %>
</li>
<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>
<%= link_to "Back", :back %>
registrations/show.html.erb
<%= image_tag #profile.photo.url %>
<br>
<%= #user.email %>
<br>
<%= #user.first_name %>
<%= #user.last_name %>
<br>
<%= #user.date_of_birth %>
<br>
<%= #user.is_female %>
registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
def show
#user = User.find(params[:id])
end
private
def sign_up_params
params.require(:user).permit(:first_name, :last_name, :is_female, :date_of_birth, :email, :password, :password_confirmation)
end
def account_update_params
params.require(:user).permit(:first_name, :last_name, :is_female, :date_of_birth, :email, :password, :password_confirmation, :current_password)
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { :registrations => 'users/registrations', :profiles => 'users/profiles' }
devise_scope :user do
get 'profiles/edit' => 'users/profiles#edit'
post 'profiles/edit' => 'users/profiles#edit'
get 'users/:id' => 'users/registrations#show', as: :user
end
root to: "home#index"
end
Error after clicking update:
Routing Error
No route matches [PATCH] "/profiles/edit.21"
I appreciate any assistance, and please let me know if any further information is needed.
Try:
patch 'profiles/:id' => 'users/profiles#update'
and form helper should like this:
<%= form_for(#profile, html: { :multipart => true }) do |f| %>
Hope it is helpful for you!!
try adding this route to devise_scope to pass that error
patch 'profiles/edit' => 'users/profiles#edit'
btw, in ProfilesController
creating new Profile should be in create action
in edit action, you should load existed profile and render edit view
Update:
form in edit view will submit data to action update, we need get profile again and update data for it
your routes is not correct, when edit a profile, we should submit to a url look like users/profiles/4/update
you can declare routes as below
devise_for :users, :controllers => { :registrations => 'users/registrations' }
namespace :users do
resources :profiles
end
In update action, you retrieve that profile p = Profile.find(params[:id]) and update it p.photo = params[:photo]; p.save or anything you want
Related
On a rails app setup with Devise, i am trying to provide users with a form to change passwords.
i have followed the solution 3 from the Devise wiki:https://github.com/heartcombo/devise/wiki/How-To:-Allow-users-to-edit-their-password
and accordingly have in a user controller
class UsersController < Devise::RegistrationsController
def update_password
#user = current_user
if #user.update(user_params)
# Sign in the user by passing validation in case their password changed
bypass_sign_in(#user)
redirect_to root_path
else
render "edit"
end
end
end
routes.rb
devise_for :users,
path: "", path_names: {
sign_in: "login",
sign_out: "logout",
sign_up: "register",
edit: "settings"
},
controllers: {
registrations: "users",
sessions: "users/sessions"
}
resources :users do
patch 'update_password'
end
Rake routes gives me :
user_update_password_path POST (/:locale)/users/:user_id/update_password(.:format)
users#update_password {:locale=>/fr|en|de/}
the link to access the menu is the following:
<%= link_to user_update_password_path(current_user) %>
in browser, that links directs me to :
http://localhost:3000/en/users/1/update_password
but I receive a Routing error
No route matches [GET] "/en/users/1/update_password"
When I wrap the
resources :users do
resources :wishlists
collection do
patch 'update_password'
end
end
the link_to send to
http://localhost:3000/1/password
Which results in the error
undefined local variable or method `user_update_password_path' for
<#:0x00007f86cfe48f10> Did you mean? user_password_path
however, rails routes shows:
update_password_users PATCH (/:locale)/users/update_password(.:format) users#update_password {:locale=>/fr|en|de/}
but a link_to
update_password_users_path
results in an error
Could not find devise mapping for path "/en/users/update_password".
This may happen for two reasons:
1) You forgot to wrap your route inside the scope block. For example:
devise_scope :user do
get "/some/route" => "some_devise_controller" end
2) You are testing a Devise controller bypassing the router. If so,
you can explicitly tell Devise which mapping to use:
#request.env["devise.mapping"] = Devise.mappings[:user]
What have I missed ?
First of all in the solution 3 it says resource not resources. Watch the differences carefully between yours and the below one -
resource :user, only: [:edit] do
collection do
patch 'update_password'
end
end
Second the like should direct to edit_user_path not update_password_user as that is the patch route.
Third, you have to add a edit action to your controller as the wiki suggests. And also a form for the action.
before_action :authenticate_user!
def edit
#user = current_user
end
and in app/views/users/edit.html.erb
<%= form_for(#user, :url => { :action => "update_password" } ) do |f| %>
<div class="field">
<%= f.label :password, "Password" %><br />
<%= f.password_field :password, :autocomplete => "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</div>
<div class="action_container">
<%= f.submit %>
</div>
<% end %>
You missed lots of things. Try reading the wiki again.
routes are correct, not sure what else is off?
upon "updating" page (when it routes to update) I get the error
param is missing or the value is empty: user
This is my second custom view page for devise the other is working with similar code.
routes-
devise_for :users, controllers: {registrations: 'users/registrations'} as :user do
end
root 'home#home'
get 'users/discovery_settings' => 'users#discovery_settings'
patch 'users/discovery_settings/update' => 'users#update_discovery'
My user controller-
def update_discovery
#user = User.find(current_user.id)
if #user.update(user_params2)
# Sign in the user by passing validation in case their password changed
sign_in #user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
def user_params2
# NOTE: Using `strong_parameters` gem
params.require(:user).permit(:discovery, :male, :female, :min_age, :max_age)
end
Then my views form_for calls the method
<%= form_for(#user, :url => { :action => "update_discovery" }, html: {class: "form floating-label"}) do |f| %>
Figured this out on my own and posted a blog about it, here was my answer:
Out of all the problems i've had customizing devise this one probably took the longest for me to figure out. A common error you will receive from doing this incorrectly is:
param is missing or the value is empty: user
1st step is to create a controller that inherits the devise controller (essentially overriding it). This should go inside controllers/users and be called registration_controller.rb .
Insert the following code for a secondary customer edit view-
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
def NAMEOFVIEW
#user = current_user
if #user
render :NAMEOFVIEW
else
render file: 'public/404', status: 404, formats: [:html]
end
end
also you'll need to sanitize any custom parameters you make in your database
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit(:username, :email, :password, :name, :user_age, :user_gender ) }
devise_parameter_sanitizer.permit(:account_update) { |u| u.permit(:username, :email, :password, :password_confirmation, :current_password, :name, :user_age, :user_gender, :user_bio ) }
end
and finally allow updates without password (by default devise forces this)
protected
def update_resource(resource, params)
resource.update_without_password(params)
end
Under routes:
Rails.application.routes.draw do
devise_for :users, controllers: {registrations: 'users/registrations'}
as :user do
match 'users/NAMEOFVIEWHERE' => 'users/registrations#NAMEOFVIEWHERE', :via => [:get], :as => 'NAMEOFVIEWHERE'
then finally any changes in your view can be done using a form_for or a form_tag, form_for example below:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put, class: " html classes here" }) do |f| %>
<div class="field">
<%= f.label :Bio %><br />
<%= f.text_area :user_bio, autocomplete: "off", class: "optional html class here", rows: 3, cols: 20, name: "description", placeholder: "About" %>
</div>
<div class="optional button class here">
<button type="submit">Save</button>
</div>
<% end %>
Now restart your rails server and cross your fingers!
routes are correct, not sure what else is off?
upon "updating" page (when it routes to update) I get the error
param is missing or the value is empty: user
This is my second custom view page for devise the other is working with similar code.
routes-
devise_for :users, controllers: {registrations: 'users/registrations'} as :user do end root 'home#home'
get 'users/discovery_settings' => 'users#discovery_settings' patch 'users/discovery_settings/update' => 'users#update_discovery'
My user controller-
def update_discovery
#user = User.find(current_user.id)
if #user.update(user_params2)
# Sign in the user by passing validation in case their password changed
sign_in #user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
def user_params2
# NOTE: Using `strong_parameters` gem
params.require(:user).permit(:discovery, :male, :female, :min_age, :max_age)
end
Then my views form_for calls the method
<%= form_for(#user, :url => { :action => "update_discovery" }, html: {class: "form floating-label"}) do |f| %>
Figured this out on my own and posted a blog about it, here was my answer:
Out of all the problems i've had customizing devise this one probably took the longest for me to figure out. A common error you will receive from doing this incorrectly is:
param is missing or the value is empty: user
1st step is to create a controller that inherits the devise controller (essentially overriding it). This should go inside controllers/users and be called registration_controller.rb .
Insert the following code for a secondary customer edit view-
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
def NAMEOFVIEW
#user = current_user
if #user
render :NAMEOFVIEW
else
render file: 'public/404', status: 404, formats: [:html]
end
end
also you'll need to sanitize any custom parameters you make in your database
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit(:username, :email, :password, :name, :user_age, :user_gender ) }
devise_parameter_sanitizer.permit(:account_update) { |u| u.permit(:username, :email, :password, :password_confirmation, :current_password, :name, :user_age, :user_gender, :user_bio ) }
end
and finally allow updates without password (by default devise forces this)
protected
def update_resource(resource, params)
resource.update_without_password(params)
end
Under routes:
Rails.application.routes.draw do
devise_for :users, controllers: {registrations: 'users/registrations'}
as :user do
match 'users/NAMEOFVIEWHERE' => 'users/registrations#NAMEOFVIEWHERE', :via => [:get], :as => 'NAMEOFVIEWHERE'
then finally any changes in your view can be done using a form_for or a form_tag, form_for example below:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put, class: " html classes here" }) do |f| %>
<div class="field">
<%= f.label :Bio %><br />
<%= f.text_area :user_bio, autocomplete: "off", class: "optional html class here", rows: 3, cols: 20, name: "description", placeholder: "About" %>
</div>
<div class="optional button class here">
<button type="submit">Save</button>
</div>
<% end %>
Now restart your rails server and cross your fingers!
Hello Stackoverflow programmer's,
I'm currently running a small side-project next to my school's project but i'm quite stuck for a while now.
Here's my problem: I have a user with some standerd attributes and that user has_one :spec. A spec is sort of an extended version for a profile.
Now this spec has as i mentioned some extra attributes, but i can't seem to assign it correctly to the current user. The strange thing is i am able to make a spec in the console.
Here's my Spec_controller:
class SpecController < ApplicationController
def index
# redirect_to :controller => "user", :action => "index"
# #user.spec = #spec.new
end
def update
#user = User.find(current_user.id)
#spec.user_id = current_user.id
#spec = current_user.spec(spec_params)
#spec = Spec.find(params[:id])
if #spec.update(params.require(:spec).permit(:first_name, :last_name, :gender, :birthdate, :occupation, :city, :state))
flash[:notice] = "Changes saved."
redirect_to users_path
else
flash[:notice] = "er ging iets mis!"
render 'edit'
end
end
def edit
#user = User.find(session[:user_id])
#spec = Spec.new
end
def new
#user = User.find(session[:user_id])
#spec = Spec.new
end
private
def spec_params
params.require(:spec).permit(:first_name, :last_name, :gender, :birthdate, :occupation, :city, :state)
end
def user_params
params.require(:user).permit(:screen_name, :email, :password)
end
end
The Spec model:
class Spec < ActiveRecord::Base
belongs_to :user
ALL_FIELDS = %w(first_name last_name occupation gender birthdate city state zip_code)
STRING_FIELDS = %w(first_name last_name occupation city state)
VALID_GENDERS = ["Male", "Female"]
START_YEAR = 1900
VALID_DATES = DateTime.new(START_YEAR)..DateTime.now
validates_inclusion_of :gender, in: VALID_GENDERS, allow_nill: false, message: "Must be male or female"
validates_inclusion_of :birthdate, in: VALID_DATES, allow_nill: false, message: "Is invalid"
end
The user model:
class User < ActiveRecord::Base
has_one :spec
validates_presence_of :email, :screen_name
validates_uniqueness_of :email, :screen_name
has_secure_password
extend FriendlyId
friendly_id :screen_name, use: :slugged
end
And the edit view in case if it's needed:
<%= form_for :spec do |form| %>
<fieldset>
<legend><%= #title %></legend>
<%= text_field_tag form, "first_name" %>
<%= text_field_tag form, "last_name" %>
<div class="form_row">
<label for="gender">Gender:</label><br>
<%= radio_button :spec, :gender, "Male" %> Male
<%= radio_button :spec, :gender, "Female" %> Female
</div>
<div class="form_row">
<label for="birthdate">Birthdate:</label><br>
<%= date_select :spec, :birthdate, :start_year => Spec::START_YEAR, :end_year => Time.now.year, :include_blank => true, :order => [:month, :day, :year] %>
</div>
<%= text_field_tag form, "occupation" %>
<%= text_field_tag form, "city" %>
<%= text_field_tag form, "state" %>
</br>
<%= submit_tag "Update", :class => "submit", :controller => :spec, :action => :update %>
</fieldset>
<% end %>
Routes file:
Rails.application.routes.draw do
resources 'spec'
#post ':controller(/:spec(/:id(.:edit)))'
get 'spec/index'
get 'spec/edit'
get 'profile/index'
get 'profile/show'
get 'profile/:screen_name', controller: 'profile', action: 'show'
resources :users, only: [:index, :new, :create, :login, :destroy, :edit, :show, :update]
controller :sessions do
get :login, to: 'sessions#new'
delete :logout, to: 'sessions#destroy'
post :authenticate, to: 'sessions#create'
end
root 'site#index'
get 'site/index'
get 'site/about'
get 'site/help'
end
I hope my code is readable, still trying to figure out alot of stuff inside of rails (first programming language).
Thanks!
Finnaly got it to work! Ive made a new def in Spec controller instead of update i made a create function. Kinda strange in the first place why i made it a update function when you want to create a complete new Spec!
Thanks alot for your help :) much appreciated.
try
#spec = current_user.spec
if #spec.update(spec_params)
...
Update:
I think the link to update spec will be something like this /specs/1/edit, getting and updating spec should be
#spec = Spec.find(params[:id])
if #spec.update(spec_params)
...
I've got a page which loads at home.html.erb and is controlled by the pages controller.
In the page, I have a form which is a single field that will be used to take email addresses.
The error I'm getting is:
undefined method `signups_path'
Here's my code for your reference, I'm not sure how exactly to define where the route is that it goes.
Home.html.erb contains this form:
<%= form_for(#signup) do |f| %>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="actions">
<%= f.submit "Enter" %>
</div>
<% end %>
The Pages controller contains:
class PagesController < ApplicationController
def home
#title = "Open Domain - Liberate your domains from obscurity"
#signup = Signup.new
end
end
The Signup controller contains:
class SignupController < ApplicationController
def show
#signup = Signup.new
end
def new
end
def create
#signup = Signup.new(params[:signup])
if #signup.save
else
render 'new'
end
end
end
And the signup model contains:
class Signup < ActiveRecord::Base
attr_accessible :email
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates(:email, :presence => true,
:length => {:maximum => 40},
:format => {:with => email_regex})
end
Any help would be hugely appreciated it. I have a feeling this is a tiny problem and I'm a beginning dev. Thanks!
The form_for(#signup) is trying to build a route to POST to. If you don't have a named route in your routes.rb, you'll get this error. Try:
routes.rb
post '/signup', :to=>"signup#create", :as=>"signups"
this basically says: When a POST to the '/signup' path is requested, route it to the create action in the signup controller. Also, make a helper to this path accessible with the name: "signups_path"
You can replace your form_for tag with this:
<%= form_for #signup, :url => { :action => "create" } do |f| %>
This will post it to "signup/create".