Rails 4 Devise: SessionsController: UnknownFormat: 406 error - ruby-on-rails

I'm trying to login with Devise, but the login fails with a 406 Not Acceptable message from Rails 4. Specifically:
Started POST "/login.user" for 127.0.0.1 at 2015-04-03 14:37:21 -0600
Processing by Devise::SessionsController#create as
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"RLOQtv2L80h1VnMKynBuGsqsTEoggZzk3dWk6h8WdfQLOaOcoznTsPDortDQD5ql8qHm52l3+qnAxTf6U+dLxQ==",
"user"=>{"email"=>"jack#example.com",
"password"=>"[FILTERED]",
"remember_me"=>"0"},
"commit"=>"Log in"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["email", "jack#example.com"]]
(0.2ms) BEGIN
Role Load (0.4ms) SELECT "roles".* FROM "roles" INNER JOIN "unities" ON "roles"."id" = "unities"."role_id" WHERE "unities"."user_id" = $1 AND (((roles.name = 'nil') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 4]]
SQL (0.5ms) UPDATE "users" SET "last_sign_in_at" = $1, "current_sign_in_at" = $2, "sign_in_count" = $3, "updated_at" = $4 WHERE "users"."id" = $5 [["last_sign_in_at", "2015-04-03 20:27:03.080761"], ["current_sign_in_at", "2015-04-03 20:37:21.763619"], ["sign_in_count", 7], ["updated_at", "2015-04-03 20:37:21.797872"], ["id", 4]]
(1.7ms) COMMIT
Completed 406 Not Acceptable in 160ms (ActiveRecord: 6.0ms)
I am trying to adapt the Sessions Controller I found here; these are the relevant parts:
class Users::SessionsController < DeviseController
prepend_before_filter :require_no_authentication, only: [:new, :create]
prepend_before_filter :allow_params_authentication!, only: :create
prepend_before_filter :verify_signed_out_user, only: :destroy
prepend_before_filter only: [:create, :destroy] { request.env["devise.skip_timeout"] = true }
# GET /resource/sign_in
def new
self.resource = resource_class.new(sign_in_params)
clean_up_passwords(resource)
yield resource if block_given?
respond_with(resource, serialize_options(resource))
end
# POST /resource/sign_in
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_flashing_format?
sign_in(resource_name, resource)
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
end
Here are the relevant routes:
Prefix Verb URI Pattern Controller#Action
new_user_session GET /login(.:format) devise/sessions#new
user_session POST /login(.:format) devise/sessions#create
destroy_user_session GET /sign_out(.:format) users/sessions#destroy
My sessions/new.html.erb view uses this form:
<%= form_for(resource, as: resource_name, url: user_session_path(resource_name)) do |f| %>
<input name="authenticity_token"
type="hidden"
value="<%= form_authenticity_token %>"/>
<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 %>
Notice I added the hidden authenticity_token in an attempt to address the 406 Not Acceptable message (I also have <%= csrf_meta_tags %> in my application.html.erb view), and from the POST I can see it's being sent.
My user model has devise: :database_authenticatable and validates_presence_of :email, :password.
I appreciate any tips or suggestions! I've tried many suggestions and there is a similar question here. I can provide any other info that might help.

I solved this problem by using the 'omniauth-google-oauth2'gem.

Related

ruby on rails devise edit not working when i use modal

I am using devise gem and Semantic UI modal.
I do sign-in and sign-up in homepage.html.erb.
I changed
devise/session/new.html.erb to devise/sesseion/_new.html.erb
so i can use <%= render devise/session/new %>
Sign-up and sign-in are working well when I use modal but edit is not working when using modal.
What is the problem in my code?
homepage.html.erb
<div class="ui longer modal">
<div>
<%= render "devise/registrations/edit" %>
</div>
</div>
devise/registrations/_edit.html.erb
<%= resource_name.to_s.humanize %>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), :html => {:remote => true, :class => 'ui form'}) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :tel %><br />
<%= f.number_field :tel, autofocus: true, placeholder: current_user.tel, autocomplete: "tel" %>
</div>
<div class="field">
<%= f.label :nickname %><br />
<%= f.text_field :nickname, autofocus: true, placeholder: current_user.nickname, autocomplete: "nickname" %>
</div>
<div class="field">
<%= f.label :profile_img %><br />
<%= f.text_field :profile_img, autofocus: true, autocomplete: "profile_img" %>
</div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div class="field">
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, autocomplete: "off" %>
<% if #minimum_password_length %>
<br />
<em><%= #minimum_password_length %> characters minimum</em>
<% end %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</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, autocomplete: "off" %>
</div>
<div class="actions">
<%= f.submit "edit" %>
</div>
<% end %>
<%= button_to "membership withdrawal", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>
route.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { :passwords => "users/passwords", :confirmations => "users/confirmations", registrations: 'users/registrations', sessions: 'users/sessions'}
devise_scope :user do
get 'registrations' => 'devise/registrations#create'
get 'users/edit' => 'devise/registrations#edit'
delete 'users/sign_out' => 'devise/sesssions#destroy'
end
application_controller.rb
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
additional_params = [:name, :tel, :nickname, :profile_img]
devise_parameter_sanitizer.permit(:sign_up, keys: additional_params)
devise_parameter_sanitizer.permit(:tel, :nickname, :password, :password_confirmation, :current_password)
end
Routes
Helper HTTP Verb Path Controller#Action
new_user_session_path GET /users/sign_in(.:format) users/sessions#new
user_session_path POST /users/sign_in(.:format) users/sessions#create
destroy_user_session_path GET /users/sign_out(.:format) users/sessions#destroy
user_password_path POST /users/password(.:format) devise/passwords#create
new_user_password_path GET /users/password/new(.:format) devise/passwords#new
edit_user_password_path GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration_path GET /users/cancel(.:format) users/registrations#cancel
user_registration_path POST /users(.:format) users/registrations#create
new_user_registration_path GET /users/sign_up(.:format) users/registrations#new
edit_user_registration_path GET /users/edit(.:format) users/registrations#edit
PATCH /users(.:format) users/registrations#update
PUT /users(.:format) users/registrations#update
DELETE /users(.:format) users/registrations#destroy
registrations_path GET /registrations(.:format) devise/registrations#create
GET /users/edit/:id(.:format) devise/registrations#edit
users_path PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) users/registrations#destroy
users_sign_out_path DELETE /users/sign_out(.:format) devise/sesssions#destroy
root_path GET / fjob#homepage
fjob_homepage_path GET /fjob/homepage(.:format) fjob#homepage
fjob_create_path GET /fjob/create(.:format) fjob#create
review_create_review_path GET /review/create_review(.:format) review#create_review
users_sign_up_path GET /users/sign_up(.:format) users#sign_up
fjob_default_fjob_path GET /fjob/default_fjob(.:format) fjob#default_fjob
GET /users/sign_out(.:format) users#sign_out
users_edit_path GET /users/edit(.:format) users#edit
application_helper.rb
module ApplicationHelper
def resource_name
:user
end
def resource
#resource ||= User.new
end
def resource_class
User
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
end
Logs
started POST "/users" for 222.98.34.68 at 2018-08-23 08:19:01 +0000
Cannot render console from 222.98.34.68! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by Users::RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "user"=>{"tel"=>"123456", "nickname"=>"123123", "profile_img"=>"", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "current_password"=>"[FILTERED]"}, "commit"=>"회원 정보 수정"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 5]]
Redirected to https://find-kim-esdx245.c9users.io/
Filter chain halted as :require_no_authentication rendered or redirected
Completed 302 Found in 3ms (ActiveRecord: 0.2ms)
Started GET "/" for 222.98.34.68 at 2018-08-23 08:19:01 +0000
Cannot render console from 222.98.34.68! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by FjobController#homepage as HTML
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 5]]
Fjob Load (0.1ms) SELECT "fjobs".* FROM "fjobs" WHERE "fjobs"."id" = ? LIMIT 1 [["id", 5]]
Rendered devise/sessions/_new.html.erb (4.9ms)
Rendered devise/registrations/_new.html.erb (4.0ms)
Rendered devise/registrations/_edit.html.erb (7.2ms)
Fjob Load (0.3ms) SELECT "fjobs".* FROM "fjobs"
Fjob Load (0.2ms) SELECT "fjobs".* FROM "fjobs" WHERE "fjobs"."id" = ? LIMIT 1 [["id", 1]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
Review Load (0.1ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."id" = ? LIMIT 1 [["id", 1]]
CACHE (0.0ms) SELECT "fjobs".* FROM "fjobs" WHERE "fjobs"."id" = ? LIMIT 1 [["id", 5]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 5]]
Review Load (0.1ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."id" = ? LIMIT 1 [["id", 5]]
Fjob Load (0.1ms) SELECT "fjobs".* FROM "fjobs" WHERE "fjobs"."id" = ? LIMIT 1 [["id", 3]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 3]]
Review Load (0.1ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."id" = ? LIMIT 1 [["id", 3]]
Rendered fjob/homepage.erb within layouts/application (25.1ms)
Completed 200 OK in 29ms (Views: 26.5ms | ActiveRecord: 1.4ms)

Rails file_field tag passing only String file name to controller

My file_field tag is only passing the file name, not the file itself to the controller.
In my User model:
mount_uploader :avatar, AvatarUploader
validate :avatar_size
...
def avatar_size
errors.add :avatar, "should be less than 5MB" if avatar.size > 5.megabytes
end
The AvatarUploader:
class AvatarUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
process resize_to_limit: [50, 50]
if Rails.env.production?
storage :fog
else
storage :file
end
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_white_list
%w(jpg, jpeg, gif, png)
end
end
And the User Controller:
before_action :logged_in_user, only: [:index, :edit, :update, :destroy, :following, :followers]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: [:destroy]
skip_before_action :verify_authenticity_token, only: [:create]
...
def update
#user = User.find(params[:id])
if #user.update_attributes user_params
flash[:success] = "Profile updated"
redirect_to user_path #user
else
render 'edit'
end
end
...
def user_params
params.require(:user).permit :name, :email, :password, :password_confirmation, :avatar
end
def correct_user
#user = User.find params[:id]
redirect_to root_path unless #user == current_user
end
def admin_user
redirect_to root_path unless current_user.admin?
end
The form in the view:
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<% if #user.avatar? %>
<%= image_tag #user.avatar.url, size: "50x50" %>
<% else %>
<%= image_tag "stock_ava.png", size: "50x50" %>
<% end %>
<%= f.file_field :avatar, accept: 'image/jpeg,image/gif,image/png' %>
<%= f.submit yield(:button_text), class: "btn btn-primary" %>
<% end %>
In the console I can see the attribute come in as "FinnJake.png", rather than the appropriate ActionDispatch.
Processing by UsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"h9tD/g2M1zJ5L4cnysIQwHCWxDdhhhJR1I9a9+FAWeT9aTXPte16Uyn8GvI4w23klfvYtTaLCDrGVonHfmFUag==", "user"=>{"name"=>"Example User", "email"=>"example#user.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "avatar"=>"FinnJake.png"}, "commit"=>"Save Changes", "id"=>"1"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
(0.1ms) begin transaction
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) AND ("users"."id" != ?) LIMIT ? [["email", "bexample#user.com"], ["id", 1], ["LIMIT", 1]]
SQL (1.1ms) UPDATE "users" SET "avatar" = ?, "updated_at" = ? WHERE "users"."id" = ? [["avatar", nil], ["updated_at", "2017-10-02 14:50:41.226691"], ["id", 1]]
(142.3ms) commit transaction
Redirected to https://rubyonrails-xxx.c9users.io/users/1
Completed 302 Found in 155ms (ActiveRecord: 144.1ms)
I'm very new to rails, but I cannot figure out why the file_field isn't uploading a file. I can see in the browser that I end up with this tag:
<input accept="image/jpeg,image/gif,image/png" type="file" name="user[avatar]" id="user_avatar">
Which looks right to me. I also cannot seem to manually update that column through the rails console, though I get no errors:
2.4.0 :002 > user = User.first
User Load (0.5ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example#user.com", created_at: "2017-10-02 14:32:22", updated_at: "2017-10-02 16:35:55", password_digest: "$2a$10$sww7gItks0mYz6xz8zV.QOIjr6to/o5Jytjmuo0wxny...", remember_digest: nil, admin: true, activation_digest: "$2a$10$W396r7A8aZaii3DC7b3W7u70etSmXh3MORMIoWtcSHo...", activated_at: "2017-10-02 14:32:22", reset_digest: nil, reset_sent_at: nil, avatar: nil>
2.4.0 :003 > user.update avatar: "String"
(0.2ms) begin transaction
User Exists (0.4ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) AND ("users"."id" != ?) LIMIT ? [["email", "example#user.com"], ["id", 1], ["LIMIT", 1]]
SQL (2.4ms) UPDATE "users" SET "updated_at" = ?, "avatar" = ? WHERE "users"."id" = ? [["updated_at", "2017-10-02 17:27:06.097363"], ["avatar", nil], ["id", 1]]
(11.4ms) commit transaction
=> true
Thanks in advance for any advice you can provide.
You should use multipart form like:
form_for(#user, html: { multipart: true }) do ...
See http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-file_field
Found the problem. See this comment
Essentially, the form in the partial was being wrapped by another form which had a different encoding type.

Why does my Registrations#Update devise action not update all attributes in my `User` model?

This is my views/devise/registrations/edit.html.erb:
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put, class: "edit-user-form m-t" }) do |f| %>
<%= f.error_notification %>
<div class="form-group">
<%= f.input_field :email, required: true, autofocus: true %>
</div>
<div class="form-group">
<%= f.input_field :current_password, hint: "we need your current password to confirm your changes", placeholder: "current password", required: true %>
</div>
<div class="form-group">
<%= f.input_field :password, autocomplete: "off", hint: "leave it blank if you don't want to change it", placeholder: "new password", required: false %>
</div>
<div class="form-group">
<%= f.input_field :password_confirmation, placeholder: "confirm new password", required: false %>
</div>
<div class="form-group">
<%= f.association :school, collection: School.where(school_type: [:college, :university]), prompt: "Choose a school", class: 'col-lg-4 form-control', label: false %>
</div>
</div>
<div class="form-group">
<div class="col-lg-12 text-center">
<%= f.button :submit, "Update", class: "btn btn-lg edit-account-update-button" %>
</div>
</div>
<% end %>
And this is my ApplicationController:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
check_authorization :unless => :devise_controller?
rescue_from CanCan::AccessDenied do |exception|
respond_to do |format|
format.json { head :forbidden }
format.html { redirect_back(fallback_location: root_path, flash: { danger: exception.message }) }
end
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:account_update, keys: [:avatar, :avatar_cache, :remove_avatar, :school_id])
end
end
The issue though is that it isn't updating the record, here is the log from that operation:
Started PUT "/users" for ::1 at 2016-11-02 19:22:59 -0500
Processing by DeviseInvitable::RegistrationsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Xo445XVpElgDmfcjywZKEbsXIqZR/2Wgw==", "user"=>{"remove_avatar"=>"0", "avatar_cache"=>"", "email"=>"coach#test.com", "current_password"=>"[FILTERED]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "school_id"=>"3"}, "commit"=>"Update"}
User Load (4.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 7], ["LIMIT", 1]]
User Load (9.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 7], ["LIMIT", 1]]
(0.7ms) BEGIN
SQL (4.2ms) UPDATE "users" SET "updated_at" = $1, "avatar" = $2 WHERE "users"."id" = $3 [["updated_at", 2016-11-03 00:22:59 UTC], ["avatar", "a1.jpg"], ["id", 7]]
(0.8ms) COMMIT
Redirected to http://localhost:3000/
Completed 302 Found in 139ms (ActiveRecord: 19.1ms)
Note that the school_id is set in the params, so we know it properly accepts the input from the form. But the SQL UPDATE statement, doesn't include school_id, so it doesn't actually save that info to the DB.
Also note that there are no unpermitted params messages in the log.
What could be causing this?
Edit 1
This is the School.rb model:
class School < ApplicationRecord
has_many :users
enum school_type: { high_school: 0, college: 1, university: 2 }
end
This is the User.rb model:
class User < ActiveRecord::Base
belongs_to :school
end
The problem was that your devise model User was inheriting ActiveRecord::Base instead of ApplicationRecord which is an abstract class in Rails 5. With the inheritance of latter, most of the gems which deal with models can and do modify the code of ActiveRecord::Base in their own context without affecting other models, which isn't possible if you inherit the former.
Source: Why Rails 5 uses ApplicationRecord instead of ActiveRecord::Base?

Ruby on Rails validate for multiple choice test

What is the best way to validate a answer input by a user, validation rules below:
Examples of formats allowed 1, 2, 3, 4...to 12
The value is 2 answers for 12 choices
model:
class Questions < ApplicationRecord
belongs_to :user
validates :user, presence: true
validates :answers, presence: true
end
Html:
<h3>question</h3>
<% (1..12).each do |x| %>
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-danger btn-circle">
<input type="checkbox" name="question[answer][]" id="optionsCheckbox<%= x %>" value="<%= x %>" />
<%= x %>
</label>
</div>
<% end %>
</ul>
<%= f.button :submit, "submit", class: "btn btn-success" %>
in controller:
class QuestionsController < ApplicationController
skip_before_action :authenticate_user!, only: [ :new ]
before_action :find_question, only: [:show, :edit, :update, :destroy]
def create
#question = Question.new(ticket_params)
#question.user = current_user
if #question.save
redirect_to new_charge_path
else
render :new, alert: "Oops, something went wrong..."
end
end
def question_params
params.require(:question).permit(answer: [])
end
def find_question
#question = Question.find(params[:id])
end
end
answer is a string in questions table
It is an array, he have 12 choices and 2 possible responses. Like a multiple choice quiz.. I would just define the possible number of choice (2 choices)
That is my submit response in console:
Started POST "/questions" for 127.0.0.1 at 2016-05-24 18:26:08 +0200
Processing by QuestionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"mAoBIf9jqDoungeeFKe6KitIf0ahAxhi6rVODmz6v1xGExYeVAVL8qXBfJj37KTpIkBBZJV2F1MRuBJKA==", "question"=>{"answer"=>["2", "8"], "commit"=>"Submit"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT 2 [["id", 6], ["LIMIT", 1]]
(0.2ms) BEGIN
SQL (27.0ms) INSERT INTO "questions" ("answer", "created_at", "updated_at", "user_id") VALUES (1, 2 ) RETURNING "id" [["answer", "[\"2\", \"8\"]"], ["created_at", 2016-05-24 16:26:08 UTC], ["updated_at", 2016-05-24 16:26:08 UTC], ["user_id", 6]]
(23.5ms) COMMIT
Redirected to http://localhost:3000/charge/new
Completed 302 Found in 112ms (ActiveRecord: 51.3ms)
Not sure I fully understand the requirement, but seems like something like this:
class Question...
validate :validate_answers
def validate_answers
unless answers.length == 2
errors.add(:answers, 'must have 2 selected')
end
end
end

Can't update user in Ruby on Rails

I am using ruby on rails try to update user information, but when I submit, the console will show an error saying the user exists and redirect to the correct page. What's wrong with my code?
The error message:
Started PATCH "/users/6" for ::1 at 2015-06-08 21:27:00 -0500
Processing by UsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"sJm38g36DAYDo4eXdpcIPRX0e40Jp6cECmMwEvhCAEhTlDwwmmgOfXZqeczglNmJ4K9pQXiyXAsRsgP/C8lScg==", "name"=>"test123", "department"=>"123", "commit"=>"Update User", "id"=>"6"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 6]] CACHE (0.0ms)
SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", "6"]] (0.1ms)
begin transaction
User Exists (0.2ms)
SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'test#test.com' AND "users"."id" != 6) LIMIT 1 (0.1ms)
rollback transaction
Redirected to http://localhost:3000/users/6
Completed 302 Found in 9ms (ActiveRecord: 0.5ms)
Started GET "/users/6" for ::1 at 2015-06-08 21:27:00 -0500
Processing by UsersController#show as HTML
Parameters: {"id"=>"6"} User Load (0.1ms)
SELECT "users".* FROM "users" WHERE "users"."id"
= ? LIMIT 1 [["id", 6]]
Rendered users/show.html.erb within layouts/application (0.1ms)
User Load (0.2ms)
SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 6]] CACHE (0.0ms)
SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 6]]
Completed 200 OK in 66ms (Views: 64.3ms | ActiveRecord: 0.3ms)
The edit page
<h1 class="center">Edit name</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_tag "/users/#{#user.id}", :method => 'patch' do %>
<p>
<%= label_tag :name %>
<%= text_field_tag :name, #user.name %>
</p>
<p>
<%= label_tag :department %>
<%= text_field_tag :department, #user.dept %>
</p>
<input type="submit" name="commit" value="Update User">
<% end %>
</div>
</div>
The controller is like this
class UsersController < ApplicationController
before_action :authorize, only: [:show, :edit, :update]
def authorize
#user = User.find_by(id: params[:id])
if #user.blank? || session[:user_id] != #user.id
redirect_to root_url, notice: "Nice try!"
end
end
def new
#user = User.new
end
def show
end
def edit
end
def update
#user = User.find_by(id: params[:id])
#user.name = params[:name]
#user.dept = params[:department]
#user.save
redirect_to user_path(#user.id)
end
def create
#user = User.new(email: params[:email],
name: params[:name],
password: params[:password],
role: params[:role],
dept: params[:dept])
if #user.save
redirect_to root_url, notice: "Thanks for signing up."
else
render "new"
end
end
end
The router concerning this part is like:
# sign up
get '/signup' => 'users#new'
post '/users' => 'users#create'
get '/users/:id' => 'users#show', as: :user
get '/users/:id/edit' => 'users#edit', as: 'edit_user'
patch '/users/:id' => 'users#update'
The problem is in the form_tag,it should be like this
<%= form_tag({:action => :update}, {:method => :patch}) do %>
Also your code for form_tag looks vulnerable. Changing it to like this will be better.
<%= form_tag update_user_path(#user) do %>
or
<%= form_tag user_path(#user), :method => :patch do %>
Are you using rails 4?
You should update your controller to conform to strong_parameters if you are.
def update
#user = User.find(params[:id)
if #user.update_attributes(user_params)
redirect_to user_path(#user.id)
else
render :edit
end
end
private
def user_params
params.require(:user).permit(:name, :dept)
end
Doing this will mean that you have to wrap your name and dept params inside a user scope, eg.
user: { name: "Howard Moon", dept: "Zookeeper" }
But is the standard way to handle params in the controller.
Hope this helps!
EDIT: Link to Strong Parameters which does a better job at explaining this than I can. Haha

Resources