I have a custom Primary Key (PK), ASIN, in my Products table. This PK is a string.
def change
create_table :products, id: false do |t|
t.references :user, null: false, foreign_key: true
t.primary_key :asin
t.string :image
t.string :price
t.string :title
t.timestamps
end
change_column :products, :asin, :string
end
In my models for Product, I have the following:
self.primary_key = 'asin'
belongs_to :user
validates_uniqueness_of :asin
validates_presence_of :asin, :image, :title, :price, :user_id
before_save :before_save
def before_save
self.asin = self.asin.upcase!
end
I have looked over the code several times but while trying to hit this Route and create a Product, this is the error I receive.
"exception": "#<ActiveRecord::NotNullViolation: SQLite3::ConstraintException: NOT NULL constraint failed: products.asin>"
And this is the JSON that I am sending to this create Route
{
"asin": "B",
"title": "Test",
"image": "test",
"user_id": 1,
"price": "test"
}
NOTE: I know that it is generally looked down upon to use PKs in this manor and please know I recognize this but this is the ideal setup for my project's goal. Please refrain from leaving mean-spirited comments.
EDIT: For reference, here is the Create function under the Products controller.
skip_before_action :authorize_request, only: [:create, :show]
def create
Product.create!(product_params)
json_response(product_params, :created)
end
def product_params
params.permit(
:asin,
:image,
:title,
:user_id,
:price
)
end
EDIT: Part of the issue was that the asin's first letter needed to be downcased before sending to the backend.
I am not totally sure what happened here to fix this. But I ran the following commands just to test things as I was sure this database setup was perfectly fine.
First, I stopped the server using control + c on mac.
I connected to rails using rails c
I connected to the products table using Product.connection
And I created a test Product just to see what was wrong Product.create!(asin: "Test_ASIN", title: "title", image: "image", price: "price", user_id: 1)
I was surprised to see that this worked since this is exactly what I sent to the backend originally, but then I went ahead and started rails s and tried to send the request again and this time, it submitted.
I hope this helps someone out there as this was obnoxiously weird.
Related
I'm taking a course on Lynda.com (Ruby on Rails 5 Essential Training) and I'm having an issue with adding a record on a table. Here's some details: The objective is to create a joint table, Many-to-Many association, so we're first trying to create a record on with of the tables we want to use on the new table. And everytime I write this line:
section = Sections.create(:name => "Section One", :position => 1)
It gives me this
(0.2ms) BEGIN
(0.3ms) ROLLBACK
=> #<Section id: nil, page_id: nil, name: "Section One", position: 1, visible: false, content_type: nil, content: nil, created_at: nil, updated_at: nil>
I checked my code and everything seems fine. By the way inserting records on other tables works. It's just this table.
one important point, This table is a previously created table. It's the new one we're trying to create.
What am I doing wrong?
Here is my code from migrate:
class CreateSections < ActiveRecord::Migration[5.2]
def up
create_table :sections do |t|
t.integer "page_id"
t.string "name"
t.integer "position"
t.boolean "visible", :default => false
t.string "content_type"
t.text "content"
t.timestamps
end
add_index("sections", "page_id")
end
def down
drop_table :sections
end
end
Here is the Section model:
class Section < ApplicationRecord
belongs_to :page
has_many :section_edits
end
The error is caused by: belongs_to :page as the page_id is nil and by default Rails belongs_to helper is adding a presence validation to make sure that the association is valid.
To disable this behaviour (presence validation) you can use:
belongs_to :page, optional: true
as mentioned here: https://guides.rubyonrails.org/association_basics.html#options-for-belongs-to
or you can add page_id to your Section.create call as mentioned by others:
page_id = 1 # or Page.first.id or any page id you need
section = Section.create(name: "Section One", position: 1, page_id: page_id)
Your error comes from belongs_to :page
If you try with create!, you should see this error message:
ActiveRecord::RecordInvalid: Validation failed: Page must exist
Just add page_id in your section creation:
page_id = 1 # or Page.first.id or any page id you need
section = Section.create(name: "Section One", position: 1, page_id: page_id)
I have a model called Issue that has the following database structure :
class CreateIssues < ActiveRecord::Migration
def change
create_table :issues do |t|
t.string :path, null: false
t.string :filename, null: false
t.string :name, null: false
t.string :year
t.integer :number
t.timestamps null: false
end
end
end
In my model tests, I use the following line :
issue = Issue.create path: "test_path", filename: "test_filename", name: "test_name"
... which raises an exception when saving :
SQLite3::ConstraintException: NOT NULL constraint failed:
issues.path: INSERT INTO "issues" ("created_at", "updated_at") VALUES (?, ?)
From what I understand, when calling create or new/save, rails starts by inserting an entry with only the timestamps. I would expect the insert to contain all of the values that I have passed to the create method. Am I missing a step in the creation process?
EDIT :
Basic information and steps:
Using SQLite3
Using Rails 4.2.1
Using RSpec
Generated the Issue model using be rails generate model Issue
Added the NULL constraints afterwords by hand
Did be rake db:migrate successfully
Tried my code in various model spec files
Tried other models, I get generated SQL that only includes the timestamps.
EDIT 2:
Here is my Issue model :
class Issue < ActiveRecord::Base
has_one :pending_issue
has_one :watched_issue
has_many :unmatched_issues
validates :path, presence: true
validates :filename, presence: true
validates :name, presence: true
attr_accessor :path
attr_accessor :filename
attr_accessor :name
attr_accessor :year
attr_accessor :number
end
Your result is anomalous. This is what I get:
# migration
class CreateIssues < ActiveRecord::Migration
def change
create_table :issues do |t|
t.string :path, null: false
t.timestamps null: false
end
end
end
Then in the console:
Issue.create path: "path"
# (0.1ms) begin transaction
# SQL (0.3ms) INSERT INTO "issues" ("path", "created_at", "updated_at") VALUES (?, ?, ?) [["path", "path"], ["created_at", "2015-06-21 16:55:08.304653"], ["updated_at", "2015-06-21 16:55:08.304653"]]
# (0.8ms) commit transaction
# => #<Issue id: 1, path: "path", created_at: "2015-06-21 16:55:08", updated_at: "2015-06-21 16:55:08">
My test:
require "test_helper"
describe Issue do
it "can be created" do
Issue.create path: "test_path"
end
end
passes. No exception.
What I think may have happened is that your database schema has become out of date on your test database.
Firstly, does a similar 'create' work in the development (default) rails console? If so, it's a big indication that something is very different in your test and development environments.
What happens if you force the console to use the test environment?
RAILS_ENV=test rails c
Does it work here?
I think you may need to manually rollback your test database to the migration which first created your issues table, then re-migrate
RAILS_ENV=test rake db:rollback
Keep applying until you reach the appropriate migration, then:
RAILS_ENV=test rake db:migrate
Does that help?
EDIT:
This appears to be the issue:
attr_accessor :path
attr_accessor :filename
attr_accessor :name
attr_accessor :year
attr_accessor :number
These will overwrite the Rails default accessors, at a guess. They are certainly not needed.
Did you accidentally omit attr_accessible for :path?
I'm having a hard time understanding how to implement a single model self-join in Rails.
The Guide to ActiveRecord Associations section 2.10 briefly explains Self-Joins but doesn't offer enough information, and every example or post about this such references the Friendly Friend Railcast example that isn't a single model self join, as described in the Rails Guide section 2.10.
The idea is a model that has_many and belongs_to itself, without needing a separate table for the relationship. The only reason I see for needing a separate table is if you want the relationship to contain more information than just the relationship. e.g. "best friends", "barely know them"
I have a simple Post schema:
create_table "posts", :force => true do |t|
t.datetime "posted"
t.string "nick"
t.string "title"
t.text "content"
t.integer "parent_post_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
The parent_post_id is a self-reference to other Post post_id's. The posts.rb model has the relationship defined:
class Post < ActiveRecord::Base
has_many :replies, :class_name => "Post"
belongs_to :parent_post, :class_name => "Post",
:foreign_key => "parent_post_id"
end
In the Controller or View I'm hoping to be able to do something like this:
#posts.each do |post|
...
#replies = post.replies
#replies.each do |reply|
...
end
end
Or find a post's parent:
#parent_post = post.parent_post
This may all be some syntax mis-understanding. So thanks in advance to anyone who can slap some sense into me. I've looked through every SO and blog post out there and none try the single model self-referential self-join method described in the Guide.
Points for anyone offering an explanation that doesn't point to the Friendly Friend example that uses a separate relationship table.
I was missing the has_many foreign key to "parent_post_id". Once its set, the post.replies will reference other Post instances by parent_post_id.
The posts.rb model has the relationship defined:
class Post < ActiveRecord::Base
has_many :replies, :class_name => "Post",
:foreign_key => "parent_post_id"
belongs_to :parent_post, :class_name => "Post",
:foreign_key => "parent_post_id"
end
I can now create Posts, assign a parent_post_id to a different Post, then later get all Posts that are replies to any parent Post.
I'm trying to build a database of urls(links). I have a Category model that has and belongs to many Links.
Here's the migration I ran:
class CreateLinksCategories < ActiveRecord::Migration
def self.up
create_table :links_categories, :id => false do |t|
t.references :link
t.references :category
end
end
def self.down
drop_table :links_categories
end
end
Here's the Link model:
class Link < ActiveRecord::Base
validates :path, :presence => true, :format => { :with => /^(#{URI::regexp(%w(http
https))})$|^$/ }
validates :name, :presence => true
has_one :category
end
Here's the category model:
class Category < ActiveRecord::Base
has_and_belongs_to_many :links
end
And here's the error the console kicked back when I tried to associate the first link with the first category:
>>link = Link.first
=> #<Link id: 1, path: "http://www.yahoo.com", created_at: "2011-01-10...
>>category = Category.first
=> #<category id : 1, name: "News Site", created_at: "2011-01-11...
>>link.category << category
=> ActiveRecord::StatementInvalid: SQLite3::Exception: no such column :
categories.link_id:
Are my associations wrong or am I missing something in the database? I expected it to find the links_categories table. Any help is appreciated.
Why are you using HABTM here at all? Just put a belongs_to :category on Link, and a has_many :links on Category. Then in the db, you don't need a join table at all, just a :category_id on the links table.
But, if you do want a HABTM here, from a quick glance, the first thing I noticed is that your join table is named incorrectly -- it should be alphabetical, categories_links.
The second thing is that you can't mix has_one and has_and_belongs_to_many. HABTM means just that -- A has many of B and A belongs to many of B; this relationship implies that the opposite must also be true -- B has many of A and B belongs to many of A. If links HABTM cateogries, then categories must HABTM links.
See http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_and_belongs_to_many
Hey all,
I'm having a pretty weird problem and am having trouble isolating the cause. I get the feeling its a simple solution, but I was hoping for a nudge in the right direction. I have the following models:
class User < ActiveRecord::Base
has_many :pnotes
class Pnote < ActiveRecord::Base
belongs_to :preport
belongs_to :user
class Preport < ActiveRecord::Base
has_many :pnotes, :dependent=>:destroy
The Pnote portion of my schema looks as so:
create_table "pnotes", :force => true do |t|
t.integer "preport_id"
t.integer "user_id"
t.text "content"
t.datetime "created_at"
t.datetime "updated_at"
end
I'm trying to display all of the Pnotes associate with a given Preport on the show page of the Preport
My Preport Controller has the following code for the show action:
def show
#board = Board.find(params[:board_id])
#preport = #board.preport
#pnotes = #preport.pnotes
#pnote=#preport.pnotes.build
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #preport }
end
end
So now in my show.html.erb in the Preports folder, I am trying to display a list of the Pnotes as such:
<ul>
<% #pnotes.each do |pnote| %>
<li><%= pnote.user.login %><span>-<%=pnote.content %></span></li>
<% end %>
</ul>
"login" is the standard field that came along with the Devise Authentication Gem.
However, this gives me the following error:
undefined method `login' for nil:NilClass
If I change the view to this:
<%= pnote.user%>-<%=pnote.content %>
I get :
#<User:0x106c25888>-Testing
, so it appears that it is identifying the associated user, but unable to grab its attributes.
Any advice would be greatly appreciated! I feel like there is a fairly small oversight going on here, but I am unable to distinguish from exactly where
Thanks!
Unless you're using a very old version of Devise that I'm not aware of, the User model wouldn't have a login attribute.
Try email instead.