I am trying to store hash password in my users table while registration. Please see my code:
users_controller.rb
def login
#title = 'Login'
#render layout: 'login'
end
def create_login
user = User.authenticate(params[:user][:username], params[:user][:password])
if user
log_in user
redirect_to '/admin'
else
flash[:danger] = 'Invalid email/password combination' # Not quite right!
redirect_to :back
end
end
def register
#user = User.new
#title = 'Register'
end
def create_register
params[:user][:uniq_id] = generate_uniq
#user = User.new(create_user_params)
#raise #user.inspect
respond_to do |format|
if #user.save
format.html { redirect_to :success, success: 'Registration was successfully created.' }
format.json { redirect_to :register, status: :created, location: #users }
else
format.html { render :register }
format.json { render json: #users.errors, status: :unprocessable_entity }
end
end
end
private
def create_user_params
params.require(:user).permit(:uniq_id, :name, :username, :email, :password, :password_confirmation, :password_salt, :dob, :address)
end
register.html.erb
<%= form_tag("/register", method: "post") do %>
<%#= form_tag(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= text_field :user, :name, placeholder:'NAME', required: true %>
<div style="position: relative;">
<span id="chk-username" style="position: absolute;font-size: 12px;right: 2%; bottom: 5%; z-index: 9; display: block;"></span>
<%= text_field :user, :username, placeholder:'USERNAME', 'data-validate':"/users/check_username", required: true %>
</div>
<div style="position: relative;">
<span id="chk-email" style="position: absolute;font-size: 12px;right: 2%; bottom: 5%; z-index: 9; display: block;"></span>
<%= text_field :user, :email, placeholder:'EMAIL', 'data-validate':"/users/check_email", required: true %>
</div>
<%= password_field :user, :password, placeholder:'PASSWORD', required: true %>
<%= password_field :user, :password_confirmation, placeholder:'CONFIRM PASSWORD', required: true %>
<div class="submit">
<input type="submit" value="REGISTER" >
<input type="button" onclick="location.href = '<%= request.base_url %>/login'" value="LOGIN" >
</div>
<p>Forgot Password ?</p>
<% end %>
user.rb
class User < ActiveRecord::Base
#has_secure_password
attr_accessor :password
before_save :encrypt_password
validates :name, presence: true
validates :name, length: { minumum:2, maximum: 30 }
validates :password, :presence =>true,
:length => { :minimum => 6, :maximum => 40 },
:confirmation =>true
validates :username, :presence => true,
:uniqueness => { :case_sensitive => false }
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
def self.authenticate(input_username, input_password)
user = find_by_username(input_username)
if user && user.password == BCrypt::Engine.hash_secret(input_password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
routes.rb
get 'register' => 'users#register'
post 'register' => 'users#create_register'
Here is my database table.
users.sql (customize table)
+----+----------+------------+-----------+----------------+
| id | name | username | password | password_salt |
+----+----------+------------+-----------+----------------+
| 1 | chinmay | chinu | NULL |$2a$10$15fWDt.. |
| 2 | sanjib | sanjib | NULL |$2a$10$85DyMr.. |
+----+----------+------------+-----------+----------------+
I get NULL value in my password column. Please help me and let me know where the error is in my code.
Your main error is that your are using attr_accessor :password to create a getter/setter for the password attribute that overrides the getter and setter that ActiveRecord creates from the database schema.
However your whole approach to password encryption is flawed - you should have password as a purely virtual attribute and name your database column password_digest or encrypted_password.
Unless its for pure learning purposes should use the has_secure_password macro that Rails provides instead of reinventing the password encryption wheel and getting hacked.
1. Add a password_digest column to user:
rails g migration AddPassWordDigestToUser password_digest:string:index
You might want to remove the password_salt column as well as it is not used by ActiveModel::SecurePassword.
class AddPassWordDigestToUser < ActiveRecord::Migration
def change
add_column :users, :password_digest, :string
add_index :users, :password_digest
remove_column :users, :password_salt
remove_column :users, :password
end
end
2. Add has_secure_password to the User model:
class User < ActiveRecord::Base
has_secure_password
end
3. RESTful routes
You may want to correct your routes so they are resource oriented and not action oriented and follow the rails conventions:
GET /registrations/new registations#new - sign up form
POST /registrations registations#create - create user
GET /sessions/new sessions#new - sign in form
POST /sessions sessions#create - sign in user
You can setup the routes with just:
resources :registrations, only: [:new, :create]
resources :sessions, only: [:new, :create]
See Rails Routing from the Outside In.
4. Binding forms and controllers.
You are setting up the controller properly however your form is not bound to the #user model instance you are creating in your controller.
This means that the values the user enters disappear after a unsuccessful form submission.
Also pay attention to the pluralization and naming of your variables! You are inconsistently using #user and #users. In this case #users will always be nil and cause an error.
app/controllers/registrations_controller.rb:
class RegistationsController < ApplicationController
def new
#user = User.new
end
def create
# Use a block instead of messing with the incoming params.
#user = User.new(user_params) do |u|
u.uniq_id = generate_uniq
end
if #user.save
respond_to do |format|
format.html { redirect_to root_path, success: "Welcome #{#user.email}" }
format.json { status: :created, location: #user }
end
else
respond_to do |format|
format.html { redirect_to :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
app/views/registrations/new.html.erb:
<%= form_for(#user, url: registrations_path) do |f| %>
<div class="row">
<%= f.label :email %>
<%= f.text_field :email %>
</div>
<div class="row">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class="row">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</div>
<% end %>
Related
I'm trying to implement a prayer request and prayer response form, much like a micropost with a comment on it. The prayer requests are created and deleted as expected, but when I try to post a prayer response, it just reloads the page with no errors and no flash saying that the post was successful. This behavior happens wether the post is valid or not (no errors for a blank response, just a reload of the page) When I use the rails console, I'm able to build and save a prayer response successfully, and it shows up on rails server. What's wrong with my form? Based on the server log, I see that when I try to post a prayer response, it's using the RequestsController instead of the PrayerResponsesController. How do I fix this?
Here's my server log errors:
Started POST "/requests" for 127.0.0.1 at 2023-01-18 16:24:36 -0600
Processing by RequestsController#create as TURBO_STREAM
Parameters: {"authenticity_token"=>"[FILTERED]", "content"=>"Prayer response...", "request_id"=>"150", "commit"=>"Respond in Prayer"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/helpers/sessions_helper.rb:18:in `current_user'
CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/helpers/sessions_helper.rb:18:in `current_user'
Completed 400 Bad Request in 4ms (ActiveRecord: 0.1ms | Allocations: 2115)
ActionController::ParameterMissing (param is missing or the value is empty: request
Did you mean? request_id):
Here's my code:
controllers/prayer_responses_controller.rb
class PrayerResponsesController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def create
#prayer_response = current_user.prayer_responses.build(prayer_response_params)
if #prayer_response.save
flash[:success] = "Prayer Response created!"
redirect_back(fallback_location: root_url)
else
render 'static_pages/requests', status: :unprocessable_entity
end
end
def destroy
#prayer_response.destroy
flash[:success] = "Prayer Response deleted"
redirect_back_or_to( root_url, status: :see_other )
end
private
def prayer_response_params
params.require(:prayer_response).permit(:content, :request_id)
end
def correct_user
#prayer_response = current_user.prayer_responses.find_by(id: params[:id])
redirect_to root_url, status: :see_other if #prayer_response.nil?
end
end
views/static_pages/requests.html.erb
<% provide(:title, "Prayer Requests") %>
<div class="row">
<aside class="col-md-4">
<section class="request-form">
<%= render 'shared/request_form' %>
</section>
</aside>
<div class="col-md-8">
<h3>Prayer Requests</h3>
<% if Request.all != nil %>
<%= render Request.all %>
<% end %>
</div>
</div>
views/requests/_request.html.erb
<li id="request-<%= request.id %>" class="requests">
<%= link_to gravatar_for(request.user, size: 50), request.user %>
<span class="user"><%= link_to request.user.name, request.user %></span>
<span class="content"><%= request.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(request.created_at) %> ago.
<% if current_user?(request.user) %>
<%= link_to "delete", request, data: { "turbo-method": :delete,
"turbo-confirm": "Are you sure?"} %>
<% end %>
</span>
<% if current_user != nil %>
<span>
<%= render 'shared/prayer_response_form', request_id: request.id %>
</span>
<span>
<% if request.prayer_responses.any? %>
<ol class="prayer_responses">
<% request.prayer_responses.reverse.each do |prayer_response| %>
<%= render prayer_response %>
<% end %>
</ol>
<% end %>
</span>
<% end %>
</li>
views/prayer_responses/_prayer_response.html.erb
<li id="prayer_response-<%= prayer_response.id %>">
<%= link_to gravatar_for(prayer_response.user, size: 30), prayer_response.user %>
<span class="user"><%= link_to prayer_response.user.name, prayer_response.user %></span>
<span class="content"><%= prayer_response.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(prayer_response.created_at) %> ago.
<% if current_user?(prayer_response.user) %>
<%= link_to "delete response", prayer_response, data: { "turbo-method": :delete,
"turbo-confirm": "Are you sure?"} %>
<% end %>
</span>
</li>
views/shared/_prayer_response_form.html.erb
<%= form_with(model: #prayer_response) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<center>
<div class="field">
<%= f.text_area(:content, placeholder: "Respond to this prayer request...") %>
</div>
<div><%= f.hidden_field :request_id, value: request_id %></div>
<%= f.submit "Respond in Prayer", class: "btn btn-primary" %>
</center>
<% end %>
models/prayer_response.rb
class PrayerResponse < ApplicationRecord
belongs_to :user
belongs_to :request
default_scope -> { order( created_at: :desc) }
validates :user_id, presence: true
validates :request_id, presence: true
validates :content, presence: true, length: { maximum: 500 }
end
models/request.rb
class Request < ApplicationRecord
belongs_to :user
has_many :prayer_responses, dependent: :destroy
default_scope -> { order(created_at: :desc) }
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 280 }
end
db/migrate/20230113172701_create_prayer_responses.rb
class CreatePrayerResponses < ActiveRecord::Migration[7.0]
def change
create_table :prayer_responses do |t|
t.text :content
t.references :user, null: false, foreign_key: true
t.references :request, null: false, foreign_key: true
t.timestamps
end
add_index :prayer_responses, [:user_id, :request_id, :created_at]
end
end
db/migrate/20230107204925_create_requests.rb
class CreateRequests < ActiveRecord::Migration[7.0]
def change
create_table :requests do |t|
t.text :content
t.references :user, null: false, foreign_key: true
t.timestamps
end
add_index :requests, [:user_id, :created_at]
end
end
config/routes.rb
root "static_pages#home"
get "/help", to: "static_pages#help"
get "/about", to: "static_pages#about"
get "/contact", to: "static_pages#contact"
get "/new_public_prayers", to: "static_pages#new_public_prayers"
get "/signup", to: "users#new"
get "/login", to: "sessions#new"
post "/login", to: "sessions#create"
delete "/logout", to: "sessions#destroy"
resources :users do
member do
get :following, :followers
end
end
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resources :prayers, only: [:create, :destroy]
resources :requests, only: [:create, :destroy]
resources :prayer_responses, only: [:create, :destroy]
resources :comments, only: [:create, :destroy]
resources :private_prayers, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
get "/private_prayers", to: "static_pages#private_prayers"
get "/prayers", to: "static_pages#home"
get "/comments", to: "static_pages#home"
get "/requests", to: "static_pages#requests"
get "/prayer_responses", to: "static_pages#requests"
end
The answer, actually, was in the static_pages_controller.rb file... I needed to add #prayer_response = current_user.prayer_responses.build to the requests page's function...
class StaticPagesController < ApplicationController
def home
if logged_in?
#prayer = current_user.prayers.build
#comment = current_user.comments.build
#feed_items = current_user.feed.paginate(page: params[:page])
end
end
def help
end
def about
end
def contact
end
def new_public_prayers
end
def private_prayers
if logged_in?
#private_prayer = current_user.private_prayers.build
else
redirect_to root_url
end
end
def requests
if logged_in?
#request = current_user.requests.build
#prayer_response = current_user.prayer_responses.build
else
redirect_to root_url
end
end
end
This made sure that the proper controller was followed when building a new prayer response, etc.
I want, that a user with the admin role can edit other users from users/index.html.erb view. I'm not the first one asking this question, but all the given answers lack clear instructions.
So the problem is; after editing the fields, when I click on the 'Updtate' button in users/index.html.erb view, the page is reloaded but no changes appens.
Aditionnal infos: I'm using Devise and Omniauth facebook.
The users are display in the users/index via a partial:
<td>
<div class="field">
<%= f.text_field :name, class: 'form-control' %>
</div>
</td>
<td>
<div class="field">
<%= f.text_field :email, class: 'form-control' %>
</div>
</td>
<td>
<div class="actions">
<%= f.submit I18n.translate('control.update'), class: 'btn sign-up-button' %>
</div>
</td>
<td>
<!-- display a delete button if the user is not the current_user -->
<%= link_to(I18n.translate('control.delete'), user_path(user), :data => { :confirm => "Are you sure?" }, :method => :delete, :class => 'btn') unless user == current_user %>
</td>
users/index.html.erb:
<div class="container">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<h2 class="text-center"><%= I18n.translate('user.users_list') %></h2>
<div class="column">
<table class="table">
<tbody>
<% #users.each do |user| %>
<tr>
<%= render user %>
</tr>
<% end %>
</tbody>
</table>
</div>
<ul class=”pagination”>
<li><%= will_paginate(#users) %></li>
</ul>
</div>
</div>
</div>
My user_controller.rb
class UsersController < ApplicationController
before_action :ensure_admin, :except => :show
def index
#users = User.paginate(:page => params[:page], :per_page => 8)
end
def show
#user = User.find_by_name(params[:id])
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update(secure_params)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
def destroy
user = User.find(params[:id])
user.destroy
redirect_to users_path, :notice => "User deleted."
end
private
def ensure_admin
if(current_user.role == 'admin')
return
end
redirect_to root_path, :alert => "Access denied."
end
def secure_params
params.require(:user).permit(:role)
end
def user_params
params.require(:user).permit(:email, :name, :password)
end
end
My routes:
Rails.application.routes.draw do
root to: 'pages#index'
get 'users/index'
# you can type '/users' to view the users
match '/users', to: 'users#index', via: 'get'
devise_for :users, :controllers => { :registrations => "registrations",
:path_prefix => 'd',
:omniauth_callbacks => "users/omniauth_callbacks" }
resources :users
scope '/:locale' do
devise_scope :user do
get 'login', to: 'devise/sessions#new'
end
devise_scope :user do
get 'signup', to: 'devise/registrations#new'
end
end
Here in the user_controller update action you are calling secure_params def, which is permitting only "role" field.
I think you should to use user_params in update action like below
def update
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
Or you will have to permit other params also in secure_params def like
def secure_params
params.require(:user).permit(:role,:name,:email)
end
Hope it would help you.
I am trying to create a login system in Rails, but, when I go to the signup page, I get an error saying : "undefined method `first_name' for #". I checked my users database for the "first_name" column, and found that the only columns in the "users" table were "id", "created_at", and "updated_at". I created my app using rails new appname -d mysql, I have the mysql2 gem, I have updated my databases.yml file, and I have run "rake db:migrate". Still, nothing works. How can I fix this? This is my users controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to '/login'
else
redirect_to '/signup'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password)
end
end
Here is my router:
Rails.application.routes.draw do
root 'main#index'
get '/login' => 'sessions#new'
get '/signup' => 'users#new'
resources :users
post 'login' => 'sessions#create'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Here is my model:
class User < ApplicationRecord
has_secure_password
end
Here is my Migration file:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.string :password_digest
t.timestamps
end
end
end
Here is my view:
<div class="login">
<div class="container">
<div class="form">
<h1>Sign up</h1>
<%= form_for(#user) do |f| %>
<%= f.text_field :first_name, :placeholder => "First name" %>
<%= f.text_field :last_name, :placeholder => "Last name" %>
<%= f.email_field :email, :placeholder => "Email" %>
<%= f.password_field :password, :placeholder => "Password" %>
<%= f.submit "Create an account", class: "btn-submit" %>
<% end %>
</div>
</div>
</div>
I am using Rails 5.0.2 on Ubuntu 16.04
You might want to try to redo the migration with db:migrate:redo, if that doesnt work, create a new migration adding the respective columns.
class CreateUsers < ActiveRecord::Migration[5.0]
def change
add_column :products, :part_number, :string
add_column :products, :price, :decimal
end
end
I'm having a problem with my research routes. they accuse this error:
ActionController::UrlGenerationError in Devise::Sessions#new
No route matches {:action=>"search", :controller=>"devise/index"}
my application:
<!DOCTYPE html>
<html>
<head>
<title>Javendi</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<div class = 'search', style="display:none">
<%= form_for root_path, :url => {:action => 'search', :controller=>"index"} do |f|%>
<%= text_field_tag "ad[price_min]", #ads_min, :placeholder => 'Price min', class: 'price' %>
<%= text_field_tag "ad[price_max]", #ads_max, :placeholder => 'Price max', class: 'price' %><br>
<%= text_field_tag "ad[title]", #ads_text, :placeholder => 'Ad name', class: 'titlesearch' %><br>
<div class='categorysearch'>
<%= collection_select :ad, :category_id, Category.all,:id,:name,:prompt => true, :selected => #ads_category_id %>
<br></div>
<%= f.submit'Searc', class: 'bottomsearch' %>
<%end%>
</div>
<div class="cima">
<!-- <img src="assets/2.gif" border="0" onmouseover="this.src='assets/7.gif'" onmouseout="this.src='assets/2.gif'"> -->
<div class= 'logout'>
<% if user_signed_in? %>
<%= link_to image_tag('exit.png', width: '50px', height:'50px'),destroy_user_session_path, method: :delete %>
<%else%>
<%end%>
</div>
<div class= "home">
<%= link_to image_tag('logo.png'),root_path %>
</div>
<div class="javendi">
<% if user_signed_in? %>
<button class= 'botton1'>
<%= link_to 'Editar Perfil', edit_user_registration_path %>|
<%= link_to 'Novo Anúncio', new_ad_path %>|
<%= link_to 'Meus Anúncios', my_ads_path %>|
<%= link_to 'Meus Favoritos', fav_ads_path %>
</button>
<%else%>
<button class= 'botton'>
<%= link_to 'Cadastre-se', new_user_registration_path %> |
<%= link_to 'Login', new_user_session_path %>
</button>
<%end%>
<div class='triangule'>
<div class="seta-cima">
</div>
</div>
</div>
<% if user_signed_in? %>
<div id='iconsearh2'>
<%= image_tag("search.png") %>
</div>
<%else%>
<div id='iconsearh'>
<%= image_tag("search.png") %>
</div>
<%end%>
</div>
<script type="text/javascript">
$('#iconsearh').click(function(){
if($('.search').is(':visible')){
$('.search').slideUp('fast')
$('.seta-cima').css("display","none");
}else{
$('.search').slideDown('fast')
$('.seta-cima').show();
}
});
</script>
<script type="text/javascript">
$('#iconsearh2').click(function(){
if($('.search').is(':visible')){
$('.search').slideUp('fast')
$('.seta-cima').css("display","none");
}else{
$('.search').slideDown('fast')
$('.seta-cima').show();
}
});
</script>
<div class='cima2'>
<div class='welcome'>
<% if current_user.present?%>
welcome <%=current_user.name%>
<%end%>
</div>
<div class= 'createad'>
<%= image_tag('7.gif', width: '50px', height:'50px')%>
</div>
</div>
<div class="results">
<%= yield %>
</div>
<div class= "bot">
 
</div>
</div>
</body>
</html>
my ads model:
class Ad < ActiveRecord::Base
validates_presence_of :title, message: "deve ser preenchido"
validates_presence_of :price, message: "deve ser preenchido"
validates_presence_of :adress, message: "deve ser preenchido"
validates_presence_of :email, message: "deve ser preenchido"
validates_presence_of :phone, message: "deve ser preenchido"
belongs_to :user
belongs_to :category
has_many :photos, :dependent => :destroy
accepts_nested_attributes_for :photos, :allow_destroy => true
has_many :user_ad_favs
def can_edit?(current_user)
if current_user.present?
return current_user.id == self.user_id
end
end
def self.search(query)
category = query[:category_id].present? ? "category_id = #{query[:category_id]}" : nil
title = query[:title].present? ? "title LIKE '%#{query[:title]}%'" : nil
price_min = query[:price_min].present? ? "price >= #{query[:price_min].to_f}" : nil
price_max = query[:price_max].present? ? "price <= #{query[:price_max].to_f}" : nil
query = [category, title, price_min, price_max].compact.join(" AND ")
return Ad.where ( query )
end
def user_fav(user)
return self.user_ad_favs.find_by_user_id_and_ad_id(user.id, self.id)
end
end
my ads controller:
class AdsController < ApplicationController
before_action :set_ad, only: [:show, :edit, :update, :destroy, :fav_ad,:unfav_ad, :search,]
# GET /ads
# GET /ads.json
def index
#ads = Ad.all
end
# GET /ads/1
# GET /ads/1.json
def show
end
# GET /ads/new
def new
#ad = current_user.ads.build
1.times { #ad.photos.build}
end
# GET /ads/1/edit
def edit
end
def search
#ads_min = params[:ad][:price_min]
#ads_max = params[:ad][:price_max]
#ads_title = params[:ad][:title]
#ads_category_id = params[:ad][:category_id]
#ads = Ad.search(params[:ad])
render :action => 'index'
end
# POST /ads
# POST /ads.json
def create
#ad = current_user.ads.build(ad_params)
respond_to do |format|
if #ad.save
format.html { redirect_to #ad, notice: 'Ad was successfully created.' }
format.json { render :show, status: :created, location: #ad }
else
format.html { render :new }
format.json { render json: #ad.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /ads/1
# PATCH/PUT /ads/1.json
def update
respond_to do |format|
if #ad.update(ad_params)
format.html { redirect_to #ad, notice: 'Ad was successfully updated.' }
format.json { render :show, status: :ok, location: #ad }
else
format.html { render :edit }
format.json { render json: #ad.errors, status: :unprocessable_entity }
end
end
end
# DELETE /ads/1
# DELETE /ads/1.json
def destroy
#ad.destroy
respond_to do |format|
format.html { redirect_to ads_url, notice: 'Ad was successfully destroyed.' }
format.json { head :no_content }
end
end
def fav_ad
user_ad_fav = #ad.user_fav(current_user)
if user_ad_fav.present?
user_ad_fav.update_attribute(:fav, true)
else
#ad.user_ad_favs.create(:user_id => current_user.id,:ad_id => #ad.id,:fav => true)
end
respond_to do |format|
format.js {render inline: "location.reload();"}
end
end
def unfav_ad
#ad.user_fav(current_user).update_attribute(:fav, false) if #ad.user_fav(current_user).present?
respond_to do |format|
format.js {render inline: "location.reload();"}
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_ad
#ad = Ad.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def ad_params
params.require(:ad).permit(:title, :price, :adress, :city, :state, :description, :email, :phone, :phone_type, :category_id, :photos_attributes =>[:photo])
end
end
You made a mistake in the :controller parameter in your form_for:
<%= form_for root_path, :url => {:action => 'search', :controller=>"index"} do |f|%>
First of all, the :controller should be 'ads' since the search action is in the AdsController you provided a sample of.
Second, you're using form_for wrong. You're passing in two different paths, root_path and the :url hash. The first parameter should be the model you're trying to make a form for. But you don't need that here, you just want a search form, so use form_tag instead:
<%= form_tag :action => 'search', :controller=>"ads" do %>
http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-form_tag
I have been trying to figure this one out for a few days now. I am using Rails 4 (with the updated mass assignment technique) and trying to use nested attributes with a many-to-many relationship. My record is saving to the DB but everything is nil and I'm getting an "Unpermitted parameters: school, alumnis, prospects" error in my logs.
Here's what I have:
referral.rb
class Referral < ActiveRecord::Base
belongs_to :school
belongs_to :alumni
belongs_to :prospect
end
alumni.rb
class Alumni < ActiveRecord::Base
has_many :referrals
has_many :prospects, through: :referrals
accepts_nested_attributes_for :referrals
end
school.rb
class School < ActiveRecord::Base
has_many :referrals
has_many :prospects, through: :referrals
has_many :alumnis, through: :referrals
accepts_nested_attributes_for :referrals
end
prospect.rb
class Prospect < ActiveRecord::Base
has_many :referrals
has_many :alumnis, through: :referrals
accepts_nested_attributes_for :referrals
end
referrals_controller.rb
def create
#referral = Referral.create(referral_params)
respond_to do |format|
if #referral.save
# ReferralMailer.referrer_email(#referral).deliver
# ReferralMailer.referral_email(#referral).deliver
format.html { redirect_to #referral, notice: 'Referral was successfully created.' }
format.json { render action: 'show', status: :created, location: #referral }
else
format.html { render action: 'new' }
format.json { render json: #referral.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_referral
#referral = Referral.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def referral_params
params.require(:referral).permit(prospects_attributes: [:first_name, :last_name, :email], alumnis_attributes: [:first_name, :last_name, :email], schools_attributes: [:name])
end
_form.html.erb
<%= form_for(#referral) do |f| %>
<% if #referral.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#referral.errors.count, "error") %> prohibited this referral from being saved:</h2>
<ul>
<% #referral.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.fields_for :school do |builder| %>
<%= builder.label :name, "School Name" %>
<%= builder.text_field :name %>
<% end %>
<%= f.fields_for :alumnis do |builder| %>
<%= builder.label :first_name, "First Name" %>
<%= builder.text_field :first_name %>
<%= builder.label :last_name, "Last Name" %>
<%= builder.text_field :last_name %>
<%= builder.label :email, "Email" %>
<%= builder.text_field :email %>
<% end %>
<%= f.fields_for :prospects do |builder| %>
<%= builder.label :first_name, "First Name" %>
<%= builder.text_field :first_name %>
<%= builder.label :last_name, "Last Name" %>
<%= builder.text_field :last_name %>
<%= builder.label :email, "Email" %>
<%= builder.text_field :email %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
server log output
Processing by ReferralsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Ee+rREUU/0wGzNFTEaMxr8oRStaA53X9fmDrlVRyrD8=", "referral"=>{"school"=>{"name"=>"asdf"}, "alumnis"=>{"first_name"=>"asdf", "last_name"=>"asfd", "email"=>"asdf"}, "prospects"=>{"first_name"=>"asdf", "last_name"=>"asdf", "email"=>"asdf"}}, "commit"=>"Create Referral"}
Unpermitted parameters: school, alumnis, prospects
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "referrals" ("created_at", "updated_at") VALUES (?, ?) [["created_at", Fri, 12 Jul 2013 03:49:06 UTC +00:00], ["updated_at", Fri, 12 Jul 2013 03:49:06 UTC +00:00]]
(0.6ms) commit transaction
(0.1ms) begin transaction
(0.1ms) commit transaction
Redirected to http://localhost:3000/referrals/68
Referral Record
=> #<Referral id: 68, created_at: "2013-07-12 03:49:06", updated_at: "2013-07-12 03:49:06", school_id: nil, alumni_id: nil, prospect_id: nil>
You should pass also 'id' in each of your nested model params try :
def referral_params
params.require(:referral).permit(prospects_attributes: [:id,:first_name, :last_name, :email], alumnis_attributes: [:id,:first_name, :last_name, :email], schools_attributes: [:id,:name])
end
Have swing
Cheers
You parameters are not being past to the controller as strong parameters is expecting.
From you server log:
"referral" => {
"school" => {
"name" => "asdf" },
"alumnis" => {
"first_name" => "asdf",
"last_name" => "asfd",
"email" => "asdf"
},
"prospects" => {
"first_name" => "asdf",
"last_name" => "asdf",
"email" => "asdf"
}
}
Strong parameters is expecting prospects_attributes, alumnis_attributes and schools_attributes so prospects, alumnis and school are getting blocked and the objects are getting created without any attributes.