I have a problem with a has_many through association.
Somehow u.groups.create!(:name => "test group", :school => "the school") makes a correct insert with the trace:
(0.1ms) begin transaction SQL (4.5ms) INSERT INTO "groups"
("created_at", "findeble", "name", "school", "updated_at") VALUES (?,
?, ?, ?, ?) [["created_at", Tue, 01 Oct 2013 08:13:36 UTC +00:00],
["findeble", false], ["name", "test group"], ["school", "the school"],
["updated_at", Tue, 01 Oct 2013 08:13:36 UTC +00:00]] SQL (0.3ms)
INSERT INTO "usergroups" ("created_at", "group_id", "updated_at",
"user_id") VALUES (?, ?, ?, ?) [["created_at", Tue, 01 Oct 2013
08:13:36 UTC +00:00], ["group_id", 7], ["updated_at", Tue, 01 Oct 2013
08:13:36 UTC +00:00], ["user_id", 1]] (0.5ms) commit transaction
=> #
But when I try via the groups_controller
# GET /groups/new
# GET /groups/new.json
def new
#group = current_user.groups.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #group }
end
end
def create
#group = current_user.groups.new(params[:group])
respond_to do |format|
if #group.save
format.html { redirect_to #group, notice: 'Group was successfully created.' }
format.json { render json: #group, status: :created, location: #group }
else
format.html { render action: "new" }
format.json { render json: #group.errors, status: :unprocessable_entity }
end
end
end
This creates the trace:
Started POST "/groups" for 127.0.0.1 at 2013-10-01 10:20:15 +0200
Processing by GroupsController#create as HTML Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"frETQoB5Mu2gLnIBG644i09XDOHFsEBTGEvrEQmfgPA=",
"group"=>{"name"=>"Test group2", "school"=>"Another school",
"findeble"=>"1"}, "commit"=>"Create Group"} User Load (0.2ms)
SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
(0.1ms) begin transaction SQL (0.8ms) INSERT INTO "groups"
("created_at", "findeble", "name", "school", "updated_at") VALUES (?,
?, ?, ?, ?) [["created_at", Tue, 01 Oct 2013 08:20:15 UTC +00:00],
["findeble", true], ["name", "Test group2"], ["school", "Another
school"], ["updated_at", Tue, 01 Oct 2013 08:20:15 UTC +00:00]]
(6.1ms) commit transaction
This only creates a new group record and not a record in the joined table. I cant understand what makes this difference.
You need to use build method:
current_user.groups.build(params[:group])
lol007 is right or you can also do it like that
In new action
#group = current_user.groups.build
And in create action
#group = current_user.groups.create(params[:group])
Related
I'm currently trying to create an Order instance. There is an association of the model Order with Items. The association is as follows. Order has many Items. I try following the documentation https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
class Order < ApplicationRecord
has_many :items
accepts_nested_attributes_for :items
end
class OrdersController < ApplicationController
##
private
def order_params
params.require(:order).permit(:description,
items_attributes: [:id, :quantity])
end
end
From the following post, it shows that the id has to be pass in the params. Rails 5 Api create new object from json with nested resource
params = {order: {description: "this is a test"}, items_attributes: [{id: 3, quantity: 3, description: 'within order -> item'}]}
=> {:order=>{:description=>"this is a test"}, :items_attributes=>[{:id=>3, :quantity=>3, :description=>"within order -> item"}]}
[7] pry(main)> order_test = Order.create!(params[:order])
(0.4ms) BEGIN
Order Create (62.9ms) INSERT INTO "orders" ("description", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["description", "this is a test"], ["created_at", "2019-05-30 23:31:39.409528"], ["updated_at", "2019-05-30 23:31:39.409528"]]
(4.6ms) COMMIT
=> #<Order:0x00007ff91556e4b8 id: 14, description: "this is a test", created_at: Thu, 30 May 2019 23:31:39 UTC +00:00, updated_at: Thu, 30 May 2019 23:31:39 UTC +00:00>
I create an order however when I check for the items it returns an empty array.
=> #<Order:0x00007ff9142da590 id: 14, description: "this is a test", created_at: Thu, 30 May 2019 23:31:39 UTC +00:00, updated_at: Thu, 30 May 2019 23:31:39 UTC +00:00>
[11] pry(main)> Order.last.items
Order Load (0.4ms) SELECT "orders".* FROM "orders" ORDER BY "orders"."id" DESC LIMIT $1 [["LIMIT", 1]]
Item Load (0.3ms) SELECT "items".* FROM "items" WHERE "items"."order_id" = $1 [["order_id", 14]]
=> []
Here is the table for items:
class CreateItems < ActiveRecord::Migration[5.2]
def change
create_table :items do |t|
t.references :order, foreign_key: true
t.integer :quantity
t.string :description
t.timestamps
end
end
end
What is wrong?
The mistake was in the order the parameters were being passed.
{:order=>{:id=>22, :description=>"this is a test", :items_attributes=>[{:order_id=>22, :quantity=>3, :description=>"within order -> item"}]}}
This solved it:
order = Order.create!(params[:order])
<Order:0x00007ff918039ee0 id: 22, description: "this is a test", created_at: Fri, 31 May 2019 01:39:23 UTC +00:00, updated_at: Fri, 31 May 2019 01:39:23 UTC +00:00>
[39] pry(main)> order.items
Item Load (114.8ms) SELECT "items".* FROM "items" WHERE "items"."order_id" = $1 [["order_id", 22]]
=> [#<Item:0x00007ff9180394b8
id: 4,
order_id: 22,
quantity: 3,
description: "within order -> item",
created_at: Fri, 31 May 2019 01:39:23 UTC +00:00,
updated_at: Fri, 31 May 2019 01:39:23 UTC +00:00>]
I'm building an invitation system where a user can either invite a friend, setting their user.id to the sender field in the database, or request an invitation, which should set the sender to '0' (an integer field).
User model
...
has_many :invites, :class_name => 'Invitation', :foreign_key => 'sender' #sent_invitations
belongs_to :invitation
...
Invitation model
belongs_to :sender, :class_name => 'User'
has_one :recipient, :class_name => 'User'
Invitations controller
def create
#invitation = Invitation.new(invitation_params)
if current_user?
#invitation.sender = current_user
if #invitation.save
redirect_to invitations_url, notice: 'Thank you. Your invitation has been sent.'
else
render action: "new"
end
else
#invitation.sender = 0
if #invitation.save
redirect_to invitations_url, notice: 'Thank you. You request is being processed..'
else
render action: "new"
end
end
end
The invitation is being created (I can see it in the database), but the sender isn't being set. This is the output form the dev_log:
Started POST "/invitations" for 127.0.0.1 at 2016-05-14 17:49:54 -0600
Processing by InvitationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"aCasBmkfw0m1T/EwuBUlXTA/z+REEWo3Hpv2HpB9w6s=", "invitation"=>{"name"=>"john", "surname"=>"public", "recipient_email"=>"jp#sasdf.com"}, "commit"=>"Create Invitation"}
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."auth_token" = 'i__MG0iqyoIND68k6qJmvw' LIMIT 1
DEPRECATION WARNING: You're trying to create an attribute `sender_id'. Writing arbitrary attributes on a model is deprecated. Please just use `attr_writer` etc. (called from create at C:/Sites/template/app/controllers/invitations_controller.rb:38)
(0.0ms) begin transaction
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."email" = 'jp#sasdf.com' LIMIT 1
SQL (1.0ms) INSERT INTO "invitations" ("created_at", "invite_token", "name", "recipient_email", "sender", "sent_at", "surname", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?) [["created_at", Sat, 14 May 2016 23:49:55 UTC +00:00], ["invite_token", "m_1zd0UxW3W1JqoDdp1EMA"], ["name", "john"], ["recipient_email", "jp#sasdf.com"], ["sender", nil], ["sent_at", nil], ["surname", "public"], ["updated_at", Sat, 14 May 2016 23:49:55 UTC +00:00]]
(0.0ms) UPDATE "users" SET "invites_avail" = 4, "updated_at" = '2016-05-14 23:49:55.161966' WHERE "users"."id" = 2
(70.0ms) commit transaction
Redirected to http://localhost:3000/invitations
Completed 302 Found in 193.0ms (ActiveRecord: 76.0ms)
I'm stumped because #1, I'm not creating an arbitrary attribute "sender_id". The applicable column in the database is "sender", and #2, the POST isn't setting the sender id, which should either be "0" or the id of the current_user.
What am I doing wrong?
I couldn't find an answer to my question, so I monkeyed it instead.
Since I'm able to get the invitation.sender to save when the invitation is sent from a current_user, and the rest were just setting nothing (NULL) in the database, I changed the query parameters in the invitations_controller.rb to look for #invitation.sender = nil for all corporate-sent invitations.
I'll leave this up until/unless someone posts a better response. Cheers!
I am calling this js from a link:
function createNewTopLevelEntry(){
var user_id = $("#user").val();
var header = prompt("Enter the name");
$.ajax( '/users/' + user_id + '/entries', {
data: {
entry: { header: header,
user: user_id } },
type: 'POST',
cache: false,
dataType: 'json',
success: displayTopLevelEntries
});
}
It hits this controller:
def create
#entry = Entry.new(params[:entry])
respond_to do |format|
if #entry.save
format.html { redirect_to #entry, notice: 'Entry was successfully created.' }
format.json { render json: #entry, status: :created, location: #entry }
else
format.html { render action: "new" }
format.json { render json: #entry.errors, status: :unprocessable_entity }
end
end
end
This is the response on the server:
Started POST "/users/1/entries" for 127.0.0.1 at 2013-03-25 21:50:36 -0700
Processing by EntriesController#create as JSON
Parameters: {"entry"=>{"header"=>"Hi", "user"=>"1"}, "user_id"=>"1"}
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "entries" ("completed", "created_at", "endtime", "header", "parent", "starttime", "starttimeset", "text", "totaltime", "updated_at", "user") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["completed", nil], ["created_at", Tue, 26 Mar 2013 04:50:36 UTC +00:00], ["endtime", nil], ["header", "Hi"], ["parent", nil], ["starttime", nil], ["starttimeset", nil], ["text", nil], ["totaltime", nil], ["updated_at", Tue, 26 Mar 2013 04:50:36 UTC +00:00], ["user", "1"]]
(2.5ms) commit transaction
Completed 500 Internal Server Error in 10ms
NoMethodError - undefined method `entry_url' for #<EntriesController:0x007fb22b9f7fd8>:
(gem) actionpack-3.2.11/lib/action_dispatch/routing/polymorphic_routes.rb:129:in `polymorphic_url'
(gem) actionpack-3.2.11/lib/action_dispatch/routing/url_for.rb:150:in `url_for'
(gem) actionpack-3.2.11/lib/action_controller/metal/rendering.rb:60:in `_process_options'
(gem) actionpack-3.2.11/lib/action_controller/metal/streaming.rb:208:in `_process_options'
(gem) actionpack-3.2.11/lib/action_controller/metal/renderers.rb:34:in `block in _handle_render_options'
What is the entry_url? Why is it looking for it? Do i need to include something in the model. Its just has attr_accessors for the vars.
class Entry < ActiveRecord::Base
attr_accessible :completed, :endtime, :header, :starttime, :starttimeset, :totaltime, :user, :text, :parent
end
Heres is my routes file:
Tasks::Application.routes.draw do
match '/users/:id/projects' => 'users#show_projects_for_user'
authenticated :user do
root :to => 'home#index'
end
root :to => "home#index"
devise_for :users
resources :users do
resources :entries
end
end
Thanks for the help.
The entry_url is what it's asking you to redirect to when you say redirect_to #entry
You don't have an entries resource in the routes file. You do have one nested within user, but then you need to pass as well as the entry.
redirect_to [ #user, #entry ]
just saw your comment - if it's doing this on the JSON path similarly you need to have
location: [#user, #entry]
Basically anywhere you're asking rails to build a url for an entry you need to pass the entry's user in because you have entry nested within user in the routes and not as a standalone resource routing.
Adding an edit to respond to the comment because there's no formatting in comments:
Yes, this it will work to delete the location as it will no longer call the helper to build that location in the json, but I am presuming you want that. So try this to make the location work:
format.json { render json => { :entry => #entry, :status => created, :location => [#user, #entry] }}
from your comment... if that's not working then let's try calling the url helper directly
format.json { render json => { :entry => #entry, :status => created, :location => user_entry_url(#user, #entry) }}
If you are using Rails3, this might case because with rails3, the url has become path
Ex:
#rails2
entry_url
#rails3
entry_path
So try entry_path instead of entry_url
I am trying to add validation to my User model, but instead of failing, the data keeps passing. For name, I have no entry. See below:
1.9.3p286 :012 > user = User.new(name: "", email: "fail#fail.com")
=> #<User id: nil, name: "", email: "fail#fail.com", created_at: nil, updated_at: nil>
1.9.3p286 :013 > user.save
(0.1ms) SAVEPOINT active_record_1
SQL (1.5ms) INSERT INTO "users" ("created_at", "email", "name", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Sun, 23 Dec 2012 18:52:00 UTC +00:00], ["email", "fail#fail.com"], ["name", ""], ["updated_at", Sun, 23 Dec 2012 18:52:00 UTC +00:00]]
(0.1ms) RELEASE SAVEPOINT active_record_1
=> true
Here is what I have in app/models/user.rb:
class User < ActiveRecord::Base
attr_accessible(:name, :email)
validates(:name, presence: true)
end
This is supposed to fail. Any suggestions? Thank you!
It should work, I think u didn't reload a console after adding a validation
I'm following this tutorial about making an Ajax request on Rails:
http://net.tutsplus.com/tutorials/javascript-ajax/using-unobtrusive-javascript-and-ajax-with-rails-3/
made _form remote:
<%= form_for(#post, :remote => true) do |f| %>
My scripts are loaded:
<script src="/assets/jquery.js?body=1" type="text/javascript"></script>
<script src="/assets/jquery_ujs.js?body=1" type="text/javascript"></script>
Added format.js to posts_controller.rb:
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.js
else
format.html { render action: "new" }
format.js
end
end
end
Created create.js.erb:
$('body').html("<h1><%= escape_javaScript(#post.title) %></h1>").append("<%= escape_javaScript(#post.content) %>");
But when I click the submit button nothing happens in the view but the posts are being created.
I just get this in the terminal:
Started POST "/posts" for 127.0.0.1 at 2012-02-06 12:58:02 +0800
Processing by PostsController#create as JS Parameters: {"utf8"=>"✓",
"authenticity_token"=>"m4BT19I9aUQ+FwGD3Ub9WqKJc0IqjsPpD8+nOyQNhjo=",
"post"=>{"name"=>"asdsad", "title"=>"sadassad",
"content"=>"adasdadadad"}, "commit"=>"Create Post"} (0.2ms) begin
transaction SQL (86.7ms) INSERT INTO "posts" ("content",
"created_at", "name", "title", "updated_at") VALUES (?, ?, ?, ?, ?)
[["content", "adasdadadad"], ["created_at", Mon, 06 Feb 2012 04:58:02
UTC +00:00], ["name", "asdsad"], ["title", "sadassad"], ["updated_at",
Mon, 06 Feb 2012 04:58:02 UTC +00:00]] (120.0ms) commit
transaction Rendered posts/create.js.erb (307.9ms) Completed 500
Internal Server Error in 528ms
ActionView::Template::Error (undefined method `escape_javaScript' for
<#:0xb78ecd0>):
1: $('body').html("<h1><%= escape_javaScript(#post.title) %></h1>").append("<%= escape_javaScript(#post.content) %>");
app/views/posts/create.js.erb:1:in
_app_views_posts_create_js_erb__76139275_96235900'
app/controllers/posts_controller.rb:45:increate'
Rendered
/home/alex/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-3.2.1/lib/action_dispatch/middleware/templates/rescues/_trace.erb
(9.9ms) Rendered
/home/alex/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-3.2.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb
(3.1ms) Rendered
/home/alex/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-3.2.1/lib/action_dispatch/middleware/templates/rescues/template_error.erb
within rescues/layout (19.1ms)
Any suggestions to fix this?
There's a typing error in that tutorial; escape_javaScript should be escape_javascript (lower case)
See also: escape_javascript()