Just started learning ruby on rails, and i created a simple shopping cart application but when i click "add to cart", i get a rollback transaction from my server. I believe the error has something to do with my orderitem controller but not sure how to fix this issue here my code.
rails server
Started POST "/order_items" for 127.0.0.1 at 2017-10-25 10:47:44 -0400
Processing by OrderItemsController#create as JS
Parameters: {"utf8"=>"✓", "order_item"=>{"product_id"=>"13", "quantity"=>"1"}, "commit"=>"Add to cart"}
(0.0ms) begin transaction
Product Load (0.5ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT ? [["id", 13], ["LIMIT", 1]]
(0.0ms) rollback transaction
Rendering order_items/create.js.erb
Rendered order_items/create.js.erb (0.5ms)
Completed 200 OK in 1028ms (Views: 605.5ms | ActiveRecord: 0.5ms)
order_items_controller.rb
class OrderItemsController < ApplicationController
def create
#order = current_order
#order_item = #order.order_items.new(order_item_params)
#order.save
session[:order_id] = #order.id
end
def update
#order = current_order
#order_item = #order.order_items.new(order_item_params)
#order_item.update_attributes(order_item_params)
#order_items = #order.order_items
end
def destroy
#order = current_order
#order_item = #order.order_items.find(params[:id])
#order_item.destroy
#order_items = #order.order_items
end
private
def order_item_params
params.require(:order_item).permit(:product_id, :quantity)
end
end
create.js.erb
<% if #order.errors.any? || #order_item.errors.any? %>
alert("Invalid")
<% else %>
$(".cart").html("<%= escape_javascript(render 'layouts/cart') %>")
<% end %>
schema.rb
ActiveRecord::Schema.define(version: 20171019015705) do
create_table "order_items", force: :cascade do |t|
t.integer "product_id"
t.integer "order_id"
t.integer "quantity"
t.float "total_price"
t.float "unit_price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "orders", force: :cascade do |t|
t.float "subtotal"
t.float "total"
t.float "shipping"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
create_table "products", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.float "price"
t.text "description"
t.string "picture"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "username"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
orderItem.rb
class OrderItem < ApplicationRecord
belongs_to :order
belongs_to :product
before_save :set_unit_price
before_save :set_total_price
def unit_price
if persisted?
self[:unit_price]
else
product.price
end
end
def total_price
unit_price * quantity
end
private
def set_unit_price
self[:unit_price] = unit_price
end
def set_total_price
self[:total_price] = quantity * set_unit_price
end
end
order.rb
class Order < ApplicationRecord
has_many :order_items
belongs_to :user
before_save :set_subtotal
def subtotal
order_items.collect {|order_item| order_item.valid? ? (order_item.unit_price*order_item.quantity) : 0}.sum
end
private
def set_subtotal
self[:subtotal] = subtotal
end
end
user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :orders
def to_param
username
end
end
carts_controller.rb
class CartsController < ApplicationController
before_action :authenticate_user!
def show
#order_items = current_order.order_items
end
end
Rails Server now
Started GET "/products" for 127.0.0.1 at 2017-10-25 11:21:11 -0400
Processing by ProductsController#index as HTML
Rendering products/index.html.erb within layouts/application
Product Load (0.0ms) SELECT "products".* FROM "products"
Rendered products/index.html.erb within layouts/application (16.0ms)
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Rendered layouts/_cart.html.erb (1.0ms)
Rendered layouts/_nav.html.erb (34.3ms)
Completed 200 OK in 604ms (Views: 571.1ms | ActiveRecord: 0.5ms)
#order_item = #order.order_items.new(order_item_params)
is creating an item only in memory. there is nothing wrong with that.but i think you need to change the new to create as so
#order_item = #order.order_items.create(order_item_params)
Related
I'm trying to build a RESTFul API with devise & jwt.
I can register, and login/logout using my jwt bear token, using Postman.
Now I have a problem when I want to POST an Article.
I dont understand why my console goes for a login after I POST an Article with Postman.
Also I dont understand why I get this 401 error. It's really hard to find some content with RESTFul + API + Devise + JWT.
Do you think it's better in the long term to run with or without Devise ? Cause there is actually some content without Devise.
What I try on Postman
Authorization : <Bearer token>
{
"title":"the title",
"content":"the content"
}
Returned ERROR message from the console when I post an Article with Postman ( and with a the same bear token as for login/logout
Started POST "/articles" for ::1 at 2021-09-01 18:07:41 +0200
Processing by ArticlesController#create as */*
Parameters: {"title"=>"the title", "content"=>"the content", "article"=>{"title"=>"the title", "content"=>"the content"}}
Completed 401 Unauthorized in 76ms (Allocations: 113)
Started GET "/api/login" for ::1 at 2021-09-01 18:07:41 +0200
Processing by SessionsController#new as JSON
Completed 200 OK in 71ms (Views: 2.5ms | Allocations: 179)
app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
before_action :set_todo, only: [:show, :update, :destroy]
before_action :authenticate_user!
# GET /todos
def index
#articles = Article.all
json_response(#articles)
end
# POST /todos
def create
#article = Article.create!(article_params)
#article.user = current_user
end
# GET /todos/:id
def show
json_response(#article)
end
# PUT /todos/:id
def update
#article.update(article_params)
head :no_content
end
# DELETE /todos/:id
def destroy
#article.destroy
head :no_content
end
private
def article_params
# whitelist params
params.permit(:title, :content, :user_id)
end
def set_article
#article = Article.find(params[:id])
end
end
db/shema.rb
ActiveRecord::Schema.define(version: 2021_09_01_124211) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "articles", force: :cascade do |t|
t.string "title"
t.text "content"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.bigint "user_id", null: false
t.index ["user_id"], name: "index_articles_on_user_id"
end
create_table "jwt_denylist", force: :cascade do |t|
t.string "jti", null: false
t.datetime "expired_at", null: false
t.index ["jti"], name: "index_jwt_denylist_on_jti"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_foreign_key "articles", "users"
end
app/models/article.rb
class Article < ApplicationRecord
belongs_to :user
end
app/models/user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:jwt_authenticatable, jwt_revocation_strategy: JwtDenylist
has_many :articles
end
I am building a feature in an app where a user can upload a resume as "pdf" with carrierwave. It should only be possible to upload one file but I can not make the record unique on the database level nor I can use unique as a validation on the model file because carrierwave does not allow it.
To solve this issue I have decided that I want to at least redirect from the new action to the show action(existing "download_file") if any record exists so the user will be not able to upload a second file into the database.
I guess my issue is that the new action finds a destroyed resume record with the id: 1 and thats why the form will not be rendered and I would not get redirected to the existing record.
How can I accomplish this? What am I missing?
resumes_contrller.rb
class ResumesController < ApplicationController
around_filter :catch_not_found
before_action :find_resume, only: [ :show, :edit, :update, :destroy]
def show
end
def new
if Resume.exists?
redirect_to Resume.find(params[:id])
else
#resume = Resume.new
end
end
def create
#resume = Resume.new resume_params
if #resume.save
redirect_to #resume
else
render :new
end
end
def edit
end
def update
if #resume.update resume_params
redirect_to #resume, notice: "Your resume was successfully saved!"
else
render 'edit'
end
end
def destroy
#resume.destroy
redirect_to new_resume_path, notice: "Your resume was successfully deleted!"
end
private
def resume_params
params.require(:resume).permit( :download_file, :remove_download_file)
end
def find_resume
#resume = Resume.find(params[:id])
end
def catch_not_found
yield
rescue ActiveRecord::RecordNotFound
redirect_to(root_url, :notice => 'Record not found')
end
end
schema.rb
ActiveRecord::Schema.define(version: 20170821213418) do
create_table "resumes", force: :cascade do |t|
t.string "download_file"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
development.log
Started GET "/resumes/new" for 77.8.47.62 at 2017-08-22 19:58:07 +0000
Cannot render console from 77.8.47.62! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by ResumesController#new as HTML
[1m[36mResume Exists (0.1ms)[0m [1mSELECT 1 AS one FROM "resumes" LIMIT 1[0m
[1m[35mResume Load (0.1ms)[0m SELECT "resumes".* FROM "resumes" WHERE "resumes"."id" = ? LIMIT 1 [["id", nil]]
Redirected to https://rails-tutorial-martinbortowski.c9.io/
Completed 302 Found in 10ms (ActiveRecord: 0.9ms)
Started GET "/" for 77.8.47.62 at 2017-08-22 19:58:08 +0000
Cannot render console from 77.8.47.62! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by WelcomesController#index as HTML
Rendered welcomes/index.html.erb within layouts/application (0.3ms)
Completed 200 OK in 59ms (Views: 58.2ms | ActiveRecord: 0.0ms)
In your code, Resume.exists? is akin to asking the question, "Is there at least one resume record in my database?"
If you examine the query it produces, you'll see something like
SELECT 1 AS one FROM `resumes` LIMIT 1
I believe what you really want to do is associate the resume to a user. As Pedro said, you'll want to set up a relation between User and Resume to keep track of the association.
Then you'll want something like
class ResumesController < ApplicationController
# ...
def new
if resume = current_user.resume
redirect_to resume
else
#resume = Resume.new
end
end
# ...
end
Using Rails 5, I have an issue when I try to save my association between these 2 models : User and Provider
My models :
class User < ApplicationRecord
# Relations
has_and_belongs_to_many :providers
end
class Provider < ApplicationRecord
# Relations
has_and_belongs_to_many :users
accepts_nested_attributes_for :users
end
the Controller :
class ProvidersController < ApplicationController
def new
#provider = current_user.providers.new
end
def create
#provider = current_user.providers.new(provider_params)
if #provider.save
redirect_to root_path
else
render :new
end
end
private
def provider_params
params[:provider][:status] = 'name'
params.require(:provider).permit(:name, :status)
end
Form :
= simple_form_for #provider do |f|
= f.error_notification
= f.input :name, required: false
= f.button :submit
On the create action, a new provider is created but it is not linked to the current user. (no data is insterted in the join table)
I have no idea why I have this behavior.
In console, if i do something like :
#user = User.create(email: "user#test.com", password: "password")
#provider = #user.providers.create(name: "Provider1", status: "name")
#provider.save
then the association is correctly saved.
> #user.providers
=> #<ActiveRecord::Associations::CollectionProxy [#<Provider id: 17, name: "Provider1", status: "name", created_at: "2017-07-25 09:37:19", updated_at: "2017-07-25 09:37:19">]>
Thanks for any idea !
For info, my schema :
create_table "providers", force: :cascade do |t|
t.string "name"
t.string "status"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "providers_users", id: false, force: :cascade do |t|
t.bigint "provider_id", null: false
t.bigint "user_id", null: false
t.index ["provider_id", "user_id"], name: "index_providers_users_on_provider_id_and_user_id"
t.index ["user_id", "provider_id"], name: "index_providers_users_on_user_id_and_provider_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
Here is the log
ÈStarted POST "/providers" for 127.0.0.1 at 2017-07-25 11:49:27 +0200
Processing by ProvidersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"27O2Tz4bbqhfRmcuq+0DIZMebSaYVc6IO/uy889Z48fF1l3c8GfIZ+WcQvZKfUeEIB5+YbrM9dON2RH47p3TIQ==", "provider"=>{"name"=>"My new provider"}, "commit"=>"Sauvegarder"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 5], ["LIMIT", 1]]
(0.2ms) BEGIN
SQL (0.4ms) INSERT INTO "providers" ("name", "status", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["name", "My new provider"], ["status", "name"], ["created_at", "2017-07-25 09:49:27.837165"], ["updated_at", "2017-07-25 09:49:27.837165"]]
(4.0ms) COMMIT
Redirected to http://localhost:3000/providers/18/steps.location
Completed 302 Found in 12ms (ActiveRecord: 5.0ms)
Started GET "/providers/18/steps.location" for 127.0.0.1 at 2017-07-25 11:49:27 +0200
Processing by Providers::StepsController#index as
Parameters: {"provider_id"=>"18"}
Redirected to http://localhost:3000/providers/18/steps/registration
Completed 302 Found in 2ms (ActiveRecord: 0.0ms)
Started GET "/providers/18/steps/registration" for 127.0.0.1 at 2017-07-25 11:49:27 +0200
Processing by Providers::StepsController#show as HTML
Parameters: {"provider_id"=>"18", "id"=>"registration"}
Provider Load (0.3ms) SELECT "providers".* FROM "providers" WHERE "providers"."id" = $1 LIMIT $2 [["id", 18], ["LIMIT", 1]]
Rendering providers/steps/registration.html.haml within layouts/provider
User Load (0.3ms) SELECT "users".* FROM "users" INNER JOIN "providers_users" ON "users"."id" = "providers_users"."user_id" WHERE "providers_users"."provider_id" = $1 [["provider_id", 18]]
Rendered providers/steps/registration.html.haml within layouts/provider (13.2ms)
Rendered shared/_head.html.haml (30.6ms) [cache miss]
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 5], ["LIMIT", 1]]
Rendered shared/_header.html.haml (9.7ms) [cache miss]
Completed 200 OK in 69ms (Views: 64.7ms | ActiveRecord: 1.1ms)
I know maybe it is not the best solution but it is the fastest that comes to my mind
def create
#provider = current_user.providers.create(provider_params)
if #provider.id
redirect_to root_path
else
render :new
end
end
This will create join table record when you use new only why that will work in case of belongs to if provider belongs to user and has user_id in migration current_user.providers.new will add user_id in the new instance, in case has and belongs to many you can do it like this, maybe there is better way but this is what came up to me first.
or something like this
def create
#provider = Provider.new(provider_params)
if #provider.save
current_user.providers << #provider
redirect_to root_path
else
render :new
end
end
one more line but I guess looks cleaner.
def create
#provider = current_user.providers.new(provider_params)
#provider.users = [current_user]
if #provider.save
redirect_to root_path
else
render :new
end
end
I suggest using a has_many through relationship instead of has_many_and_belongs_to, because you can query the join table, and possibly add some more columns in the future in this join table, should the need arise.
P.S. This feels like a Rails bug / feature improvement to me. #provider.users = [current_user] should not be needed anymore as #provider = current_user.providers.new(provider_params) can already be inferred that the #provider object is associated already with current_user, and thus should be automatically assigned already. This already works with has_many though. Seems that only here in HABTM that it does not automatically assign.
My user id isn't saving and I do not understand why.
I added the associations to both models and added the user_id to the notification params but the user id does not save automatically.
The campus_id relation does work properly and I do not really see the difference. What could be the problem? I am using a postgress database.
rails server log
Rendered /usr/local/rvm/gems/ruby-2.1.1#rails4/gems/actionpack-4.0.2/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (59.4ms)
Started POST "/campus/1/notifications" for 84.193.153.106 at 2014-10-18 19:41:03 +0000
Started POST "/campus/1/notifications" for 84.193.153.106 at 2014-10-18 19:41:03 +0000
Processing by NotificationsController#create as HTML
Processing by NotificationsController#create as HTML
Parameters: {"utf8"=>"_", "authenticity_token"=>"L9RH3hZyAKqzq9/kuJJDNaEHNVca2DbQSKSZLc8iTuw=", "notification"=>{"post"=>"thisisatest"}, "commit"=>"Maak notificatie", "campu_id"=>"1"}
Parameters: {"utf8"=>"_", "authenticity_token"=>"L9RH3hZyAKqzq9/kuJJDNaEHNVca2DbQSKSZLc8iTuw=", "notification"=>{"post"=>"thisisatest"}, "commit"=>"Maak notificatie", "campu_id"=>"1"}
Campus Load (0.6ms) SELECT "campus".* FROM "campus" WHERE "campus"."id" = $1 LIMIT 1 [["id", "1"]]
Campus Load (0.6ms) SELECT "campus".* FROM "campus" WHERE "campus"."id" = $1 LIMIT 1 [["id", "1"]]
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
(0.2ms) BEGIN
(0.2ms) BEGIN
SQL (134.0ms) INSERT INTO "notifications" ("campus_id", "created_at", "post", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["campus_id", 1], ["created_at", Sat, 18 Oct 2014 19:41:03 UTC +00:00], ["post", "thisisatest"], ["updated_at", Sat, 18 Oct 2014 19:41:03 UTC +00:00]]
SQL (134.0ms) INSERT INTO "notifications" ("campus_id", "created_at", "post", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["campus_id", 1], ["created_at", Sat, 18 Oct 2014 19:41:03 UTC +00:00], ["post", "thisisatest"], ["updated_at", Sat, 18 Oct 2014 19:41:03 UTC +00:00]]
(42.1ms) COMMIT
(42.1ms) COMMIT
Redirected to https://sl-backoffice-c9-christoph88.c9.io/notifications/9
Redirected to https://sl-backoffice-c9-christoph88.c9.io/notifications/9
Completed 302 Found in 188ms (ActiveRecord: 177.4ms)
Completed 302 Found in 188ms (ActiveRecord: 177.4ms)
Notification model
class Notification < ActiveRecord::Base
belongs_to :campus
belongs_to :user
validates :post, presence: true
validates :campus_id, presence: true
end
User model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable
has_many :notifications
has_many :spotlights
end
notifications controller
class NotificationsController < ApplicationController
before_action :set_notification, only: [:show, :edit, :update, :destroy]
before_action :set_campus, only: [:index, :new, :create]
before_action :authenticate_user!
def index
#notifications = #campus.notifications
end
def show
#campus = #notification.campus
end
def new
#notification = #campus.notifications.build
end
def edit
end
def create
#notification = #campus.notifications.build(notification_params)
respond_to do |format|
if #notification.save
format.html { redirect_to #notification }
format.json { render action: 'show', status: :created, location: #notification }
flash[:success] = 'Notification was successfully created.'
else
format.html { render action: 'new' }
format.json { render json: #notification.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #notification.update(notification_params)
format.html { redirect_to #notification }
format.json { head :no_content }
flash[:success] = 'Notification was successfully updated.'
else
format.html { render action: 'edit' }
format.json { render json: #notification.errors, status: :unprocessable_entity }
end
end
end
def destroy
#notification.destroy
respond_to do |format|
format.html { redirect_to campu_notifications_url(#notification.campus_id) }
format.json { head :no_content }
flash[:error] = 'Notification was successfully deleted.'
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_notification
#notification = Notification.find(params[:id])
end
def set_campus
#campus = Campus.find(params[:campu_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def notification_params
params.require(:notification).permit(:post, :campus_id, :user_id)
end
end
schema.rb
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20141018121628) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "campus", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "collis", force: true do |t|
t.string "name"
t.text "teaser"
t.text "description"
t.string "coursetype"
t.text "target"
t.string "campus"
t.datetime "startdate"
t.datetime "created_at"
t.datetime "updated_at"
t.string "guid"
end
create_table "coursespotlights", force: true do |t|
t.boolean "spotlight"
t.integer "colli_id"
t.datetime "start"
t.datetime "stop"
t.string "colli_guid"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "coursespotlights", ["colli_id"], name: "index_coursespotlights_on_colli_id", using: :btree
create_table "notifications", force: true do |t|
t.text "post"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "campus_id"
t.integer "user_id"
end
add_index "notifications", ["campus_id"], name: "index_notifications_on_campus_id", using: :btree
add_index "notifications", ["user_id"], name: "index_notifications_on_user_id", using: :btree
create_table "spotlights", force: true do |t|
t.boolean "spotlight"
t.datetime "start"
t.datetime "stop"
t.string "name"
t.text "teaser"
t.datetime "coursedate"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "campus_id"
t.integer "user_id"
end
add_index "spotlights", ["user_id"], name: "index_spotlights_on_user_id", using: :btree
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end
Because user_id is not a part of your parameters
From the log:
Parameters: {"utf8"=>"_", "authenticity_token"=>"L9RH3hZyAKqzq9/kuJJDNaEHNVca2DbQSKSZLc8iTuw=", "notification"=>{"post"=>"thisisatest"}, "commit"=>"Maak notificatie", "campu_id"=>"1"}
then the line from the strong params filters out unwanted content
params.require(:notification).permit(:post, :campus_id, :user_id)
this means only "notification"=>{"post"=>"thisisatest"} part will be allowed
then from the sql insert:
SQL (134.0ms) INSERT INTO "notifications" ("campus_id", "created_at", "post", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["campus_id", 1], ["created_at", Sat, 18 Oct 2014 19:41:03 UTC +00:00], ["post", "thisisatest"], ["updated_at", Sat, 18 Oct 2014 19:41:03 UTC +00:00]]
you have campus_id here because you are doing the update on #campus:
#campus.notifications.build(notification_params)
so, just make sure user_id comes in as part of notification and that is it!
(Edit: added development.log logs, "Unpermitted parameters: email")
Devise was working fine but I deleted all users using rails console and tried to make a new user. I get an error that email can't be blank. When I remove the :validatable block I get this error.
I tried to go back to commits but the error exists on all other commits. I am not sure if its something to do with the database.
My project can be found here (I pushed the last commit). I am not sure where the problem is and what I can copy for devise. I have put some code here which may show the problem.
I was able to create a user through rails console using:
u = User.new(:email => "user#name.com", :username => "test", :password => 'password', :password_confirmation => 'password')
u.save
Logs when trying to signup:
Processing by Devise::RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"WQkgKxF8rIB1wAq8vnz4Y0bCv9Txlyv0eO8IyEmpEAk=", "user"=>{"email"=>"user#example.com", "username"=>"test", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
Unpermitted parameters: email
User.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :omniauthable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :provide, :uid, :name, :email, :password, :password_confirmation, :remember_me, :username
validates_presence_of :username
has_many :posts
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.username = auth.info.nickname
end
end
def self.new_with_session(params, session)
if session["devise.user_attributes"]
new(session["devise.user_attributes"], without_protection: true) do |user|
user.attributes = params
user.valid?
end
else
super
end
end
def password_required?
super && provider.blank?
end
def update_with_password(params, *options)
if encrypted_password.blank?
update_attributes(params, *options)
else
super
end
end
end
schema.rb
ActiveRecord::Schema.define(:version => 20131118165834) do
create_table "photo_posts", :force => true do |t|
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
end
create_table "posts", :force => true do |t|
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "content_type"
t.integer "content_id"
end
add_index "posts", ["content_type", "content_id"], :name => "index_posts_on_content_type_and_content_id"
add_index "posts", ["user_id"], :name => "index_posts_on_user_id"
create_table "title_posts", :force => true do |t|
t.string "body"
end
create_table "users", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", :default => 0, :null => false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "username"
t.string "provider"
t.string "uid"
t.string "name"
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
end
logs:
Started POST "/users" for 127.0.0.1 at 2013-11-24 00:23:12 +0000
Processing by Devise::RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"awAC+Cn3qQgv2kMwZOlH8Zo60BuV4T41OnKjgvKeytE=", "user"=>{"email"=>"user#example.com", "username"=>"stttt", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
Unpermitted parameters: email
[1m[36m (0.0ms)[0m [1mbegin transaction[0m
[1m[35m (0.0ms)[0m rollback transaction
Rendered devise/shared/_links.erb (1.0ms)
Rendered devise/registrations/new.html.erb within layouts/application (15.0ms)
Rendered layouts/_header.html.erb (4.0ms)
Rendered layouts/_footer.html.erb (0.0ms)
Completed 200 OK in 178.0ms (Views: 72.0ms | ActiveRecord: 0.0ms)
Found what the error is. I use strong parameters and that causes an error. More at https://github.com/plataformatec/devise#strong-parameters
So the solution is to add this into your application_controller.rb
# Rails 3.x.x and older
before_filter :configure_permitted_parameters, if: :devise_controller?
# Rails 4.x.x and newer
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation) }
end
Keep in mind to configure for each action like :sign_in, :sign_up, :account_update etc.
The above answer is different for Devise 4 and Rails 5 now.
According to the documentation:
The Parameter Sanitaizer API has changed for Devise 4
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
end
end
Rails 5, Undefined method `for' for #<Devise on line devise_parameter_sanitizer.for