Rails: Create action not saving has_many through associations - "rollback transaction" - ruby-on-rails

Be easy on me, I'm just starting to learn Rails and this is my first question on here!
The project I'm using to learn is a volleyball scoreboard, so right now I'm trying to build a form that will submit the score of a 2v2 game. I have users and games which are associated by a has_many through relationship to a join table of participants which also includes a 'result' attribute ('W' or 'L').
My problem is that when I submit it fails, and no participants are created. If I removed the associations from the form, submission will work with just game parameters.
Hopefully, I've included all the relevant information below. Also, if there is a better way to do all this, I'd love to hear it!
MODELS
class Game < ApplicationRecord
has_one :venue
has_many :participants
has_many :users, through: :participants
accepts_nested_attributes_for :participants,
reject_if: :all_blank, allow_destroy: true
end
class User < ApplicationRecord
has_many :participants
has_many :games, through: :participants
end
class Participant < ApplicationRecord
belongs_to :game
belongs_to :user
end
SCHEMA
create_table "games", force: :cascade do |t|
t.date "game_date"
t.integer "winning_score"
t.integer "losing_score"
t.text "notes"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "venue_id"
t.index ["venue_id"], name: "index_games_on_venue_id"
end
create_table "participants", force: :cascade do |t|
t.integer "user_id"
t.integer "game_id"
t.string "result"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["game_id"], name: "index_participants_on_game_id"
t.index ["user_id"], name: "index_participants_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.string "remember_digest"
t.index ["email"], name: "index_users_on_email", unique: true
end
create_table "venues", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
CONTROLLER
class GamesController < ApplicationController
def show
#game = Game.find(params[:id])
end
def new
#users = User.all
#game = Game.new
#game.participants.build
end
def create
#game = Game.new(game_params)
if #game.save
redirect_to 'show'
else
render 'new'
end
end
private
def game_params
params.require(:game).permit(:game_date, :winning_score,
:losing_score, :notes, :venue_id,
participants_attributes: [:user_id, :result,
:_destroy])
end
end
FORM
<%= simple_form_for #game do |f| %>
<div id="winners">
<b>Winners</b>
<% for i in 0..1 %>
<%= f.simple_fields_for :participants do |p| %>
<%= p.association :user, :collection => #users, label: false %>
<%= p.input :result, :as => :hidden, :input_html => { :value => 'W' }%>
<% end %>
<% end %>
</div>
<%= f.input :winning_score, :collection => 15..30 %>
<div id="losers">
<b>Losers</b>
<% for i in 2..3 %>
<%= f.simple_fields_for :participants do |p| %>
<%= p.association :user, :collection => #users, label: false %>
<%= p.input :result, :as => :hidden, :input_html => { :value => 'L' }%>
<% end %>
<% end %>
</div>
<%= f.input :losing_score, :collection => 0..30 %>
<%= f.input :notes %>
<%= f.submit "Submit!", class: "btn btn-primary" %>
<% end %>
RESPONSE
Processing by GamesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"p8081+wU7EqYV7PIIAOGP3N+Md4CJusFpL9qTm3CeC54fP7pTPEwtfYS5v5x+ErBWxGiB0oj1pklYGXwl/cRBw==", "game"=>{"participants_attributes"=>{"0"=>{"user_id"=>"3", "result"=>"W"}, "1"=>{"user_id"=>"2", "result"=>"W"}, "2"=>{"user_id"=>"1", "result"=>"W"}, "3"=>{"user_id"=>"6", "result"=>"W"}}, "winning_score"=>"18", "losing_score"=>"4", "notes"=>"13241234"}, "commit"=>"Submit!"}
(0.1ms) begin transaction
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
User Load (0.0ms) 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", 6], ["LIMIT", 1]]
(0.1ms) rollback transaction
Rendering games/new.html.erb within layouts/application
Rendered games/new.html.erb within layouts/application (69.4ms)
Rendered layouts/_shim.html.erb (0.4ms)
Rendered layouts/_header.html.erb (0.7ms)
Rendered layouts/_footer.html.erb (0.3ms)
Completed 200 OK in 199ms (Views: 144.9ms | ActiveRecord: 0.5ms)

#kkulikovskis comment worked for me. I changed:
has_many :participants
to
has_many :participants, inverse_of: :game
in the game model

Related

Rails rolling back twice every time I try to post Data

I am trying to create an app that allows users to make lists of items and view only the lists they themselves have created. Every time I press submit on the form this happens
Started POST "/lists" for 127.0.0.1 at 2017-08-18 15:56:40 -0400
Processing by ListsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"VnsMdQq3mw5XabkYCZFTgvgwFc3H89paHA0VE5gunFbiMfa0xGr0p1GEZDHc3yemwBx07K1h4CXuS0l5XL1VbA==", "list"=>{"income"=>"12", "put_into_savings"=>"12", "month"=>"12", "year"=>"21"}, "commit"=>"Create List"}
(0.1ms) begin transaction
(0.1ms) rollback transaction
(0.0ms) begin transaction
(0.0ms) rollback transaction
Rendering lists/new.html.erb within layouts/application
Rendered lists/new.html.erb within layouts/application (9.3ms)
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 5], ["LIMIT", 1]]
Completed 200 OK in 269ms (Views: 222.2ms | ActiveRecord: 2.7ms)
Here is all my code:
lists_controller.rb
class ListsController < ApplicationController
def show
#user = User.find(params[:id])
#lists = #user.lists
end
def new
end
def edit
end
def create
#list = List.create(list_params)
if #list.save
redirect_to home_url
else
render :new
end
end
private
def list_params
params.require(:list).permit(:income, :put_into_savings, :month, :year)
end
end
lists/new.html.erb
<%= form_for List.new do |f| %>
<div class="field">
<%= f.label :income %><br />
<%= f.text_field :income %>
</div>
<div class="field">
<%= f.label :put_into_savings %><br />
<%= f.text_area :put_into_savings %>
</div>
<div class="field">
<%= f.label :month %><br />
<%= f.number_field :month %>
</div>
<div class="field">
<%= f.label :year %><br />
<%= f.number_field :year %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
schema.rb
ActiveRecord::Schema.define(version: 20170818185700) do
create_table "items", force: :cascade do |t|
t.string "item_name"
t.integer "item_cost"
t.string "item_waste"
t.string "item_group"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "lists", force: :cascade do |t|
t.integer "income"
t.integer "put_into_savings"
t.string "month"
t.string "year"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "Item_id"
t.integer "User_id"
end
create_table "users", force: :cascade do |t|
t.string "email"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
end
end
Routes.rb
Rails.application.routes.draw do
root 'home#index'
get 'home' => 'home#index'
resources :lists
resources :sessions, only: [:new, :create, :destroy]
resources :users, only: [:new, :create]
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Here is my list model:
class List < ApplicationRecord
has_many :items
belongs_to :user
end
How can I solve this?
You are having logic problem with your model association.
Assuming that a List could have more than one Item, you shouldn't have declared your table List with the attribute item_id. (Doing that it means a List could ONLY have one item). I recommend you read ruby-on-rais-guide-for-associations.
For the problem with the user_id, you need to explicit declared the user_id in your list object (considering that you want to associate a List with a User in the moment the List is created). One way to do it could be:
def create
#list = List.new(list_params)
#list[:user_id] = current_user.id # Considering you add this method
if #list.save
redirect_to home_url
else
render :new
end
And add some validation in model:
class List < ApplicationRecord
has_many :items
belongs_to :user
validates :user_id, presence: true
end
It seems you need to read more about validation too ruby-on-rais-guide-for-validation. About your twice rollback, it is unclear the reason, but fixing you association and validations problems, I think you can fix it.
Try read more about rails, the problem you are having are really basic. Good luck!
UPDATE:
As suggested by at0misk answer, to solve the problem with twice rollback:
In List controller:
#list = List.new(list_params)
# instead of #list = List.create(list_params)
The create method create a new object and save immediately. So, rails was trying to save twice, in the method create first, then in the method save in sequence.
In your create method, you're calling create and then calling save. Create creates an object and saves it to the database, so calling save is redundent.
Have you checked to see if your record is saving? If it is then this is definitely what's wrong. I prefer to use this pattern, using new instead of create, and then attempting to save in an if block:
def create
#list = List.new(list_params)
if #list.save
redirect_to home_url
else
render :new
end
end

Rails multi page form with multiple models [duplicate]

I'm getting a rollback when trying to add a user to my DB and I'm not sure why.
I have three models:
company.rb
class Company < ActiveRecord::Base
acts_as_paranoid
has_many :locations, dependent: :destroy
has_many :users, dependent: :destroy
has_many :tests, through: :locations
has_many :reports, dependent: :destroy
accepts_nested_attributes_for :locations, :users
validates_presence_of :name
end
** user.rb **
class User < ActiveRecord::Base
acts_as_paranoid
devise :database_authenticatable,
:recoverable,
:rememberable,
:trackable,
:validatable,
:registerable
belongs_to :company
has_and_belongs_to_many :roles
end
** location.rb **
class Location < ActiveRecord::Base
acts_as_paranoid
belongs_to :company
has_many :network_hosts, dependent: :destroy
has_many :tests, dependent: :destroy
has_many :commands, dependent: :destroy
validates_presence_of :company, :identifier, :name
validates_uniqueness_of :identifier
delegate :security_percentage, to: :last_test, allow_nil: true
after_initialize :generate_identifier, if: -> { self.identifier.blank? }
def generate_identifier
self.identifier = SecureRandom.uuid.delete("-")
end
So, when a user wants to signup they need to enter company, location, and user information, which is controlled by my company_controller.rb
** company_controller.rb **
class CompanyController < ApplicationController
def new
#company = Company.new
1.times { #company.locations.build }
1.times { #company.users.build }
end
def create
#company = Company.new(company_params)
if #company.save
redirect_to root_url
else
render :new
end
end
private
def company_params
params.require(:company).permit(:name, locations_attributes: [:name], users_attributes: [:first_name, :last_name, :full_name, :email, :password, :password_confirmation])
end
end
The form is using the standard form_for with nested attributes so that I can hopefully make everything in one shot when the user clicks the submit button
** company/new.html.erb **
<%= form_for #company, :url => url_for( :controller => 'company', :action => 'new' ) do |f| %>
<div class="form-group">
<%= f.label "Company Name" %>
<%= f.text_field :name, class: "form-control", placeholder: "ACME Inc." %>
<%= f.fields_for :locations do | location_builder | %>
<%= location_builder.label "Location Name" %>
<%= location_builder.text_field :name, class: "form-control", placeholder: "Main Building" %>
<% end %>
</div>
<div class="form-group">
<%= f.fields_for :users do | user_builder | %>
<%= user_builder.label "First Name" %>
<%= user_builder.text_field :first_name, class: "form-control", placeholder: "John" %>
<%= user_builder.label "Last Name" %>
<%= user_builder.text_field :last_name, class: "form-control", placeholder: "Smith" %>
<%= user_builder.label "Full Name" %>
<%= user_builder.text_field :full_name, class: "form-control", placeholder: "John Smith" %>
<%= user_builder.label "Email" %>
<%= user_builder.email_field :email, class: "form-control", placeholder: "john#acme.com" %>
<%= user_builder.label "Password" %>
<%= user_builder.password_field :password, class: "form-control" %>
<%= user_builder.label "Confirm Password" %>
<%= user_builder.password_field :password_confirmation, class: "form-control" %>
<% end %>
</div>
<%= f.submit "Submit", class: "btn btn-large btn-success" %>
<% end %>
However, I'm getting a rollback in the logs that this isn't happening and can't figure out why.
Started POST "/signup" for 127.0.0.1 at 2015-08-07 13:49:22 -0400
Processing by CompanyController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"2OHwJ9UfEbfkZHjLdm9BfOd7jlRdvoEz0L4NRJCKl64=", "company"=>{"name"=>"ACME Brick", "locations_attributes"=>{"0"=>{"name"=>"Main House"}}, "users_attributes"=>{"0"=>{"first_name"=>"Testin", "last_name"=>"User", "full_name"=>"Test User", "email"=>"test#test.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}}}, "commit"=>"Submit"}
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL AND "users"."id" = 7 ORDER BY "users"."id" ASC LIMIT 1
Role Load (0.3ms) SELECT "roles".* FROM "roles" INNER JOIN "roles_users" ON "roles"."id" = "roles_users"."role_id" WHERE "roles"."deleted_at" IS NULL AND "roles_users"."user_id" = $1 [["user_id", 7]]
(0.1ms) BEGIN
Location Exists (0.3ms) SELECT 1 AS one FROM "locations" WHERE "locations"."identifier" = '3b7febb35ea740488788d43fcc5e989c' LIMIT 1
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'test#test.com' LIMIT 1
(0.1ms) ROLLBACK
Rendered company/new.html.erb within layouts/application (5.0ms)
Completed 200 OK in 108ms (Views: 32.2ms | ActiveRecord: 1.9ms | Solr: 0.0ms)
** Company Table **
class CreateCompanies < ActiveRecord::Migration
def change
create_table :companies do |t|
t.string :name
t.timestamps
end
end
end
** Location Table **
class CreateLocations < ActiveRecord::Migration
def change
create_table :locations do |t|
t.belongs_to :company, index: true
t.string :identifier
t.string :name
t.timestamps
end
end
end
** User Table **
class CreateUsers < ActiveRecord::Migration
def self.up
create_table(:users) do |t|
t.belongs_to :company, index: true
t.string :username
t.string :first_name
t.string :last_name
t.string :full_name
t.string :time_zone, :default => "Central Time (US & Canada)"
t.string :avatar_file_name
t.string :avatar_content_type
t.integer :avatar_file_size
t.datetime :avatar_updated_at
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :phone_number
t.string :encrypted_password, :null => false, :default => ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Token authenticatable
t.string :authentication_token
t.timestamps
end
add_index :users, :email, :unique => true
add_index :users, :reset_password_token, :unique => true
create_table :roles_users, :id => false do |t|
t.references :role, :user
end
end
def self.down
drop_table :users
drop_table :roles_users
end
end
** The error from logs **
Started POST "/signup" for 127.0.0.1 at 2015-08-07 18:12:54 -0400
Processing by CompanyController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"aAc83zKKlV4w1i2GhTqTo3ehtXP+tPvYbBBRq1ccYzA=", "company"=>{"name"=>"Test Co.", "locations_attributes"=>{"0"=>{"name"=>"Main"}}, "users_attributes"=>{"0"=>{"first_name"=>"John", "last_name"=>"Smith", "full_name"=>"John Smith", "email"=>"john#acme.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}}}, "commit"=>"Submit"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL AND "users"."id" = 7 ORDER BY "users"."id" ASC LIMIT 1
Role Load (0.3ms) SELECT "roles".* FROM "roles" INNER JOIN "roles_users" ON "roles"."id" = "roles_users"."role_id" WHERE "roles"."deleted_at" IS NULL AND "roles_users"."user_id" = $1 [["user_id", 7]]
(0.1ms) BEGIN
Location Exists (0.3ms) SELECT 1 AS one FROM "locations" WHERE "locations"."identifier" = '0d759e5405084663a1c110d37f04573a' LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'john#acme.com' LIMIT 1
(0.1ms) ROLLBACK
Completed 422 Unprocessable Entity in 75ms
** [Airbrake] Notice was not sent due to configuration:
Environment Monitored? false
API key set? true
ActiveRecord::RecordInvalid (Validation failed: Locations company can't be blank):
app/controllers/company_controller.rb:10:in `create'
app/controllers/application_controller.rb:95:in `set_time_zone'
Rendered /Users/godzilla/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/actionpack-4.1.7/lib/action_dispatch/middleware/templates/rescues/_source.erb (0.9ms)
Rendered /Users/godzilla/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/actionpack-4.1.7/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.7ms)
Rendered /Users/godzilla/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/actionpack-4.1.7/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.2ms)
Rendered /Users/godzilla/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/actionpack-4.1.7/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (15.6ms)
It references that the location identifier already exists, but it doesn't. This is something that is made on the fly when trying to create a new Location (notice the method generate_identifier in the location.rb model). On top of that, the user doesn't exist either.
Any ideas how to get around this problem?
When you write validates_presence_of :company it means that your company record has to exist at the time of location creation, but it is not fully saved yet. However, your location is still associated with the company object, and it will be saved correctly without this validation. I think you can validate on presence of company_id instead because company id becomes available during saving.

Saving Signature Pad JSON in Rails Database

I'm using the wonderful Thomas Bradley Signature Pad plugin but having some issues saving the JSON signature to my users table (PSQL).
Here's relevant user controller actions:
def edit
#user = current_user
end
def update
#user = current_user
if #user.update_attributes(user_params)
redirect_to dashboard_path
else
render :edit
end
end
protected
def user_params
params.require(:user).permit(
:first_name, :last_name, :phone, :email, :password_digest, :address, :city, :province, :signature)
end
Here's my form:
<%= form_for #user, :html => {:class => "signature"} do |f| %>
<div class="form-group" style="width:205px; height: 60px;">
<%= f.label :signature, "Signature" %>
<ul class="sigNav">
<li class="clearButton">Clear</li>
</ul>
<div class="sig sigWrapper">
<div class="typed"></div>
<canvas class="pad" width="200" height="53"></canvas>
<%= f.hidden_field :signature, :class=>"output", :name=>"output" %>
</div>
</div>
<div class="spacer clearfix"></div>
<div class="form-group">
<%= f.submit "Save", :class=>"btn btn-primary" %>
</div>
<% end %>
<script>
$(document).ready(function () {
$('.signature').signaturePad({drawOnly:true});
});
</script>
When I save the form, I get no errors but the singature JSON isn't saved. No errors in the log either. When I binding.pry, I can see all the params are going through except when I type user_params, the signature is not showing up..
Anything obviously wrong in my code?
EDIT: Adding User Model, User Schema, and Log:
User.rb:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :patients
has_many :assessments, dependent: :destroy
validates :email, presence: true
validates :password, presence: true
end
User Schema:
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "password_digest"
t.string "phone"
t.string "city"
t.string "postal"
t.string "province"
t.string "address"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
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"
end
LOG when I try to update the User:
Started PATCH "/users/1" for ::1 at 2015-05-28 13:53:39 -0700
Processing by UsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ZbHqJwkOAZdYwAsTBFPIINE38uwidtUevU2/bWmgeBenXGViy3gDRbj1m5Oe3OUEWa1JkNGFHMRb4sMNnidt0A==", "user"=>{"first_name"=>"Jackson", "last_name"=>"", "email"=>"jackson#gmail.com", "phone"=>"", "address"=>"", "city"=>"", "province"=>""}, "signature"=>"[{\"lx\":52,\"ly\":27,\"mx\":52,\"my\":26},{\"lx\":51,\"ly\":26,\"mx\":52,\"my\":27},{\"lx\":47,\"ly\":28,\"mx\":51,\"my\":26},{\"lx\":38,\"ly\":32,\"mx\":47,\"my\":28},{\"lx\":30,\"ly\":34,\"mx\":38,\"my\":32},{\"lx\":20,\"ly\":37,\"mx\":30,\"my\":34},{\"lx\":14,\"ly\":38,\"mx\":20,\"my\":37},{\"lx\":10,\"ly\":39,\"mx\":14,\"my\":38},{\"lx\":9,\"ly\":39,\"mx\":10,\"my\":39},{\"lx\":11,\"ly\":34,\"mx\":9,\"my\":39},{\"lx\":15,\"ly\":27,\"mx\":11,\"my\":34},{\"lx\":20,\"ly\":18,\"mx\":15,\"my\":27},{\"lx\":27,\"ly\":11,\"mx\":20,\"my\":18},{\"lx\":34,\"ly\":5,\"mx\":27,\"my\":11},{\"lx\":41,\"ly\":0,\"mx\":34,\"my\":5},{\"lx\":46,\"ly\":-2,\"mx\":41,\"my\":0},{\"lx\":50,\"ly\":3,\"mx\":50,\"my\":2},{\"lx\":50,\"ly\":14,\"mx\":50,\"my\":3},{\"lx\":50,\"ly\":31,\"mx\":50,\"my\":14},{\"lx\":50,\"ly\":42,\"mx\":50,\"my\":31},{\"lx\":50,\"ly\":51,\"mx\":50,\"my\":42},{\"lx\":50,\"ly\":58,\"mx\":50,\"my\":51},{\"lx\":53,\"ly\":50,\"mx\":53,\"my\":49},{\"lx\":54,\"ly\":43,\"mx\":53,\"my\":50},{\"lx\":58,\"ly\":36,\"mx\":54,\"my\":43},{\"lx\":63,\"ly\":28,\"mx\":58,\"my\":36},{\"lx\":67,\"ly\":21,\"mx\":63,\"my\":28},{\"lx\":70,\"ly\":17,\"mx\":67,\"my\":21},{\"lx\":72,\"ly\":15,\"mx\":70,\"my\":17},{\"lx\":73,\"ly\":13,\"mx\":72,\"my\":15},{\"lx\":74,\"ly\":13,\"mx\":73,\"my\":13},{\"lx\":75,\"ly\":11,\"mx\":74,\"my\":13},{\"lx\":75,\"ly\":14,\"mx\":75,\"my\":11},{\"lx\":75,\"ly\":24,\"mx\":75,\"my\":14},{\"lx\":74,\"ly\":36,\"mx\":75,\"my\":24},{\"lx\":72,\"ly\":47,\"mx\":74,\"my\":36},{\"lx\":71,\"ly\":56,\"mx\":72,\"my\":47},{\"lx\":57,\"ly\":50,\"mx\":57,\"my\":49},{\"lx\":51,\"ly\":41,\"mx\":57,\"my\":50},{\"lx\":45,\"ly\":37,\"mx\":51,\"my\":41},{\"lx\":39,\"ly\":31,\"mx\":45,\"my\":37},{\"lx\":36,\"ly\":29,\"mx\":39,\"my\":31},{\"lx\":33,\"ly\":26,\"mx\":36,\"my\":29},{\"lx\":32,\"ly\":23,\"mx\":33,\"my\":26},{\"lx\":31,\"ly\":21,\"mx\":32,\"my\":23},{\"lx\":30,\"ly\":19,\"mx\":31,\"my\":21},{\"lx\":34,\"ly\":19,\"mx\":30,\"my\":19},{\"lx\":40,\"ly\":19,\"mx\":34,\"my\":19},{\"lx\":47,\"ly\":19,\"mx\":40,\"my\":19},{\"lx\":63,\"ly\":19,\"mx\":47,\"my\":19},{\"lx\":78,\"ly\":20,\"mx\":63,\"my\":19},{\"lx\":90,\"ly\":21,\"mx\":78,\"my\":20},{\"lx\":98,\"ly\":21,\"mx\":90,\"my\":21},{\"lx\":104,\"ly\":21,\"mx\":98,\"my\":21},{\"lx\":106,\"ly\":21,\"mx\":104,\"my\":21}]", "commit"=>"Save", "id"=>"1"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
(0.2ms) BEGIN
(0.2ms) ROLLBACK
Rendered users/edit.html.erb within layouts/application (2.8ms)
Rendered layouts/_nav.html.erb (1.3ms)
Rendered layouts/_flash_messages.html.erb (0.1ms)
Completed 200 OK in 651ms (Views: 644.3ms | ActiveRecord: 0.9ms)
#TomDalling solved the issue for me. Turned out to be a really simple issue when I was submitting the data.
Save a JSON array to database in rails with strong_params
It's because output is not inside the user attributes. You have:
{
"first_name" => "Jackson",
"last_name" => "Cunningham",
// etc.
},
"output" => "asasfafsafs"
But what you actually want is:
{
"first_name" => "Jackson",
"last_name" => "Cunningham",
"output" => "asasfafsafs",
// etc.
}
So in your HTML form, then name should be <input name="user[output]"> instead of <input name="output">.

Can't link user_id to new created object - rails 4

i am new to rails so any help would be much appreciated. I have the models userrs (recruiters) and adverts. Userr has_many adverts and Advert belongs to a user.
Question: when a userr creates an advert i want the created advert to
be automatically linked to the userr that created the advert. I am
unsure how to go about this in the controller
i know how to assign an advert to a user in the console. but unsure how to do this in the controller
console
advert = Advert.first
advert.userr_id = 3
advert.save
route
Rails.application.routes.draw do
resources :adverts
resources :feedbacks
devise_for :userrs
devise_for :userjs
root 'static_pages#homepg'
get 'affiliate', to: 'static_pages#affiliatepg'
get 'terms', to: 'static_pages#termpg'
get 'privacy', to: 'static_pages#privacypg'
get 'contact', to: 'static_pages#contactpg'
get 'about', to: 'static_pages#aboutpg'
get 'recruiters', to: 'static_pages#recruiterpg'
get 'jobseekers', to: 'static_pages#jobseekerpg'
get 'approach', to: 'static_pages#approachpg'
get 'sector', to: 'static_pages#sectorpg'
get 'news', to: 'static_pages#newspg'
get 'offer', to: 'static_pages#offerpg'
get 'refferal', to: 'static_pages#refferalpg'
end
i placed the below code:
in my advert controller under the create function:
def create
#userr = Userr.find(params[:userr_id])
#advert = #userr.adverts.build(params[:advert])
if #advert.save
flash[:notice] = 'Successfully created advert'
redirect_to recruiters_path
else
render action: 'new'
end
end
but i got the error:
Couldn't find Userr without an ID
log - error message
Started GET "/adverts/new" for 127.0.0.1 at 2015-04-02 14:59:38 +0100
Processing by AdvertsController#new as HTML
Completed 404 Not Found in 1ms (ActiveRecord: 0.0ms)
ActiveRecord::RecordNotFound (Couldn't find Userr without an ID):
app/controllers/adverts_controller.rb:20:in `new'
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_source.erb (8.2ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_trace.html.erb (3.4ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_request_and_response.html.erb (0.8ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_web_console.html.erb (0.8ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/diagnostics.html.erb within rescues/layout (27.3ms)
Started GET "/adverts/new" for 127.0.0.1 at 2015-04-02 14:59:38 +0100
Processing by AdvertsController#new as HTML
Completed 404 Not Found in 1ms (ActiveRecord: 0.0ms)
ActiveRecord::RecordNotFound (Couldn't find Userr without an ID):
app/controllers/adverts_controller.rb:20:in `new'
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_source.erb (8.1ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_trace.html.erb (3.0ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_request_and_response.html.erb (0.9ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_web_console.html.erb (0.8ms)
Rendered /Users/ARTLoe/.rvm/gems/ruby-2.1.2/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/diagnostics.html.erb within rescues/layout (26.2ms)
Schema
ActiveRecord::Schema.define(version: 20150330233948) do
create_table "adverts", force: true do |t|
t.string "title"
t.text "content"
t.integer "category_jobtype_id"
t.integer "category_positiontype_id"
t.integer "salarystart"
t.integer "salaryend"
t.integer "category_country_id"
t.string "city"
t.string "town"
t.string "postcode"
t.integer "category_editorialapproval_id"
t.integer "category_applicationrequest_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "userr_id"
end
create_table "userrs", 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"
t.datetime "updated_at"
t.string "firstname"
t.string "lastname"
t.string "companyname"
t.integer "category_businesstype_id"
end
add_index "userrs", ["email"], name: "index_userrs_on_email", unique: true
add_index "userrs", ["reset_password_token"], name: "index_userrs_on_reset_password_token", unique: true
model
class Advert < ActiveRecord::Base
belongs_to :user
end
class Userr < ActiveRecord::Base
has_many :adverts
end
controller: Advert
class AdvertsController < ApplicationController
respond_to :html, :xml, :json
before_action :set_advert, only: [:show, :edit, :update, :destroy]
def index
#adverts = Advert.all
respond_with(#adverts)
end
def show
respond_with(#advert)
end
# def new
# #advert = Advert.new
# respond_with(#advert)
# end
def new
#userr = Userr.find(params[:userr_id])
#advert = #userr.adverts.build
respond_with(#advert)
end
def edit
end
# def create
# #advert = Advert.new(advert_params)
# #advert.save
# respond_with(#advert)
# end
def create
#userr = Userr.find(params[:userr_id])
#advert = #userr.adverts.build(params[:advert])
if #advert.save
flash[:notice] = 'Successfully created advert'
redirect_to recruiters_path
else
render action: 'new'
end
end
def update
#advert.update(advert_params)
respond_with(#advert)
end
def destroy
#advert.destroy
respond_with(#advert)
end
private
def set_advert
#advert = Advert.find(params[:id])
end
def advert_params
params.require(:advert).permit(:title, :content, :category_jobtype_id, :category_positiontype_id, :salarystart, :salaryend, :category_country_id, :city, :town, :postcode, :category_editorialapproval_id, :category_applicationrequest_id)
end
end
form for advert
<%= simple_form_for(#advert) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :title %>
<%= f.input :content %>
<%= f.association :category_jobtype, collection: CategoryJobtype.all, prompt: "select a category" %>
<%= f.association :category_positiontype, collection: CategoryPositiontype.all, prompt: "select a category" %>
<%= f.input :salarystart %>
<%= f.input :salaryend %>
<%= f.association :category_country, collection: CategoryCountry.all, prompt: "select a category" %>
<%= f.input :city %>
<%= f.input :town %>
<%= f.input :postcode %>
<%= f.association :category_editorialapproval, as: :radio_buttons %>
<%= f.association :category_applicationrequest, as: :radio_buttons %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
any help will be appreciated
First, you need to add userr_id to params:
def advert_params
params.require(:advert).permit(:userr_id, :title, :content, :category_jobtype_id, :category_positiontype_id, :salarystart, :salaryend, :category_country_id, :city, :town, :postcode, :category_editorialapproval_id, :category_applicationrequest_id)
end
Second, add userr_id to the form:
<%= simple_form_for(#advert) do |f| %>
<%= f.hidden_field(:userr_id) %>
Third, change the param name in create:
def create
#userr = Userr.find(params[:advert][:userr_id])
You can do the same via routes, without altering the form. It's much cleaner but needs more source changes. I can't give you the full syntax here, but it will look like the following:
#routes.rb
resources :userrs do
resources :addverts
end
And the advert's form will become /userrs/[user-id]/adverts, so you'll be able to get the user id from the url instead of the form field. But you'll need to change all the path shortcuts.

Couldn't find Object without an ID

This is driving mi crazy. I don't know what I'm doing wrong, I'm getting this error:
ActiveRecord::RecordNotFound in AppointmentsController#new
Couldn't find Schedule without an ID
app/controllers/appointments_controller.rb:25:in `new'
I'm sure is a simple thing but I can't see it. Please can somebody point me the issue and how to solve it?
Here is my code
Routes.rb
scope ":locale", locale: /#{I18n.available_locales.join("|")}/ do
root :to => "Doctors#index"
resources :specialties
resources :branches
resources :doctors do
resources :appointments
resources :schedules
end
end
match '*path', to: redirect("/#{I18n.default_locale}/%{path}")
match '', to: redirect("/#{I18n.default_locale}")
Relationship
Class Appointment ...
belongs_to :doctor
belongs_to :schedule
end
Class Schedule ...
belongs_to :doctor
has_many :appointments
end
Class Doctor ...
has_many :appointments, dependent: :destroy
has_many :schedules, dependent: :destroy
end
schema
create_table "appointments", :force => true do |t|
t.integer "doctor_id"
t.date "adate"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.time "atime"
t.string "personal_id"
t.string "insurance_id"
t.string "prescription"
t.string "email"
t.string "full_name"
t.integer "schedule_id"
end
create_table "doctors", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "schedule"
t.string "prefix"
end
create_table "schedules", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "doctor_id"
t.boolean "sun"
t.boolean "mon"
t.boolean "tue"
t.boolean "wed"
t.boolean "thu"
t.boolean "fri"
t.boolean "sat"
end
Controller
def new
#schedule = Schedule.find(params[:schedule_id])
#doctor = Doctor.find(params[:doctor_id])
#appointment = #doctor.appointments.new
end
_form
<h1><%= #doctor.name %></h1>
<%= simple_form_for([#doctor, #appointment], :html => { :multipart => true, :class => 'form-horizontal' }) do |f| %>
<%= f.error_notification %>
<%= f.input :full_name %>
<%= f.input :email %>
<%= f.input :adate, as: :date_picker %>
<%= f.input :atime, as: :time_picker %>
<%= f.input :personal_id %>
<%= f.input :insurance_id %>
<%= f.input :prescription %>
<div class="controls"><%= f.button :submit, class: "btn btn-primary" %></div>
<% end %>
rails console test:
Loading development environment (Rails 3.2.11)
1.9.3p125 :001 > s = Schedule.last
Schedule Load (4.2ms) SELECT "schedules".* FROM "schedules" ORDER BY "schedules"."id" DESC LIMIT 1
=> #<Schedule id: 2, created_at: "2013-01-23 08:40:14", updated_at: "2013-01-23 08:40:14", doctor_id: 1, sun: true, mon: true, tue: true, wed: true, thu: true, fri: true, sat: true>
1.9.3p125 :002 > s.appointments
Appointment Load (0.7ms) SELECT "appointments".* FROM "appointments" WHERE "appointments"."schedule_id" = 2
=> []
root /:locale(.:format) Doctors#index
specialties GET /:locale/specialties(.:format) specialties#index
POST /:locale/specialties(.:format) specialties#create
new_specialty GET /:locale/specialties/new(.:format) specialties#new
edit_specialty GET /:locale/specialties/:id/edit(.:format) specialties#edit
specialty GET /:locale/specialties/:id(.:format) specialties#show
PUT /:locale/specialties/:id(.:format) specialties#update
DELETE /:locale/specialties/:id(.:format) specialties#destroy
branches GET /:locale/branches(.:format) branches#index
POST /:locale/branches(.:format) branches#create
new_branch GET /:locale/branches/new(.:format) branches#new
edit_branch GET /:locale/branches/:id/edit(.:format) branches#edit
branch GET /:locale/branches/:id(.:format) branches#show
PUT /:locale/branches/:id(.:format) branches#update
DELETE /:locale/branches/:id(.:format) branches#destroy
doctor_appointments GET /:locale/doctors/:doctor_id/appointments(.:format) appointments#index
POST /:locale/doctors/:doctor_id/appointments(.:format) appointments#create
new_doctor_appointment GET /:locale/doctors/:doctor_id/appointments/new(.:format) appointments#new
edit_doctor_appointment GET /:locale/doctors/:doctor_id/appointments/:id/edit(.:format) appointments#edit
doctor_appointment GET /:locale/doctors/:doctor_id/appointments/:id(.:format) appointments#show
PUT /:locale/doctors/:doctor_id/appointments/:id(.:format) appointments#update
DELETE /:locale/doctors/:doctor_id/appointments/:id(.:format) appointments#destroy
doctor_schedules GET /:locale/doctors/:doctor_id/schedules(.:format) schedules#index
POST /:locale/doctors/:doctor_id/schedules(.:format) schedules#create
new_doctor_schedule GET /:locale/doctors/:doctor_id/schedules/new(.:format) schedules#new
edit_doctor_schedule GET /:locale/doctors/:doctor_id/schedules/:id/edit(.:format) schedules#edit
doctor_schedule GET /:locale/doctors/:doctor_id/schedules/:id(.:format) schedules#show
PUT /:locale/doctors/:doctor_id/schedules/:id(.:format) schedules#update
DELETE /:locale/doctors/:doctor_id/schedules/:id(.:format) schedules#destroy
doctors GET /:locale/doctors(.:format) doctors#index
POST /:locale/doctors(.:format) doctors#create
new_doctor GET /:locale/doctors/new(.:format) doctors#new
edit_doctor GET /:locale/doctors/:id/edit(.:format) doctors#edit
doctor GET /:locale/doctors/:id(.:format) doctors#show
PUT /:locale/doctors/:id(.:format) doctors#update
DELETE /:locale/doctors/:id(.:format) doctors#destroy
/*path(.:format) :controller#:action
/ :controller#:action
appointment_steps GET /appointment_steps(.:format) appointment_steps#index
POST /appointment_steps(.:format) appointment_steps#create
new_appointment_step GET /appointment_steps/new(.:format) appointment_steps#new
edit_appointment_step GET /appointment_steps/:id/edit(.:format) appointment_steps#edit
appointment_step GET /appointment_steps/:id(.:format) appointment_steps#show
PUT /appointment_steps/:id(.:format) appointment_steps#update
DELETE /appointment_steps/:id(.:format) appointment_steps#destroy

Resources