I am running into an error after generating a new scaffold for a table with an existing model: NOT NULL constraint failed: questions.question_text.
This has been covered before, but I have not seen an answer for when there is a set null value, as I have done below.
First, I had already generated a model/migration for this table entitled Questions, which looks like:
..._create_questions.rb
class CreateQuestions < ActiveRecord::Migration
def change
create_table :questions do |t|
t.belongs_to :category, index: true
t.string :question_text, :null => false
t.timestamps
end
end
end
Notice here that I am specifying the null => false. To save some time, I ran a Scaffold command to allow me to enter data into Questions easily:
rails generate scaffold Questions --skip
After restarting the server, I am running into the error above. Since I am directly addressing the null value, I am unclear of why it triggers an error when I reach the block in QuestionsController#create (in other words, when I try to create a Question).
In case it helps, here is my Question.rb model as well:
class Question < ActiveRecord::Base
has_many :quiz_questions
has_many :quizzes, through: :quiz_questions
has_many :answers
belongs_to :category
accepts_nested_attributes_for :answers
end
What am I doing wrong?
If you are using not-null as a form of validation than you would want to add a model validation which enforces this rule as well:
class Question < ActiveRecord::Base
# ...
validates_presence_of :question_text
end
This will prevent database driver level exceptions and provide user feedback.
Since you ran the scaffold generator without any attributes I'm guessing that the params whitelist might be empty as well which would cause the above validation to fail since the input is never actually passed to the initializer.
class QuestionsController < ApplicationController
def create
#question = Question.create(question_params)
# ...
end
private
def question_params
params.require(:question)
.permit(
:category_id,
:question_text
answers_attributes: [:foo, :bar, :baz]
)
end
end
Related
I created a model(post) having two parents Community and User.
Now i want that It could be possible that community_id field may or maynot be filled so i run a migration stating change_column_null and change_column_default for community_id 's null to be allowed and default value to be zero
Now error is that community should exist so should i create a community of id=0 in rails console,is it a good practice?
or Am I doing something wrong in following code below,in allowing null true???
Post.rb(model)
class Post < ApplicationRecord
belongs_to :user
belongs_to :community
end
migration:
class Postcommunityidallownull < ActiveRecord::Migration[5.1]
def change
change_column_null :posts, :community_id, true
change_column_default :posts,:community_id, 0
end
end
When you want an optional belongs_to:
1) Just don't add in the field's migration
null: false
2) In the model use
belongs_to :community, optional: true
I've done about a billion searches and tried a number of things here but I'm still getting errors. I've recently changed to a has many through via a model called joinable(maybe thats the problem) and I can't seem to get things working straight. Part of me thinks it something small as I get the idea of it all but I'm not sure I've done it correctly. I'm also using devise.
Here is what I think are all the relevant portions
User
class User < ActiveRecord::Base
acts_as_voter
has_many :joinables
has_many :pits, through: :joinables
has_many :comments
enum role: [:user, :vip, :admin]
after_initialize :set_default_role, :if => :new_record?
class Pit < ActiveRecord::Base
validates :topic, :author, :summary, presence: true
acts_as_taggable
acts_as_votable
has_many :comments
has_many :joinables
has_many :users, through: :joinables
mount_uploader :image, ImageUploader
I created a separate table called "joinable" and now I'm stuck figuring out how to populate it. I can create a user, but can't create a pit. Do I need to revamp my controllers or is their something small I may be missing? I get the idea but some of the little details are fuzzy based on all that I've read so far. I even tried a HABTM with a join table called Pit_Users.
I'm currently getting "Could not find table 'joinables"
coming from here in my controller
def create
#pit = current_user.pits.create(pit_params)
recent migration
class Joinable < ActiveRecord::Migration
create_table :joinable do |t|
t.integer :pit_id, :user_id
t.timestamps
end
end
I've tried a number of combinations all with similar errors. Many of the tutorials/guides are good with the basics but then seem to be leaving out a few details. That or I'm just missing them. Anyways. Would love it if someone more knowledgeable could point out what are probably obvious mistakes. Thanks.
In the migration file, it should be:
class Joinables < ActiveRecord::Migration
create_table :joinables do |t|
t.integer :pit_id
t.integer :user_id
end
end
And in the app/models/joinable.rb, there should be:
class Joinable < ActiveRecord::Base
belongs_to :user
belongs_to :pit
end
You can verify if it is working at the Rails console. Try this to get a Pit record with the association:
user_1 = User.create( ... )
pit_1 = user_1.pits.create!( ... )
pit_1.users.first # should give you user as user_1
Solution is to run rails generator for model
Run from console
rails generate model Joinable pit:references user:references
And delete your migration file for
class Joinable < ActiveRecord::Migration
create_table :joinable do |t|
t.integer :pit_id, :user_id
t.timestamps
end
end
After running rails generator you will get model named Joinable that is required for relations when using through and it will create appropriate migration for you.
class AddRatingToBooks < ActiveRecord::Migration
def up
add_column :books, :rating, :integer
end
def down
remove_column :books, :rating
end
I have the following snippet of code in my db/migrate/, I'm trying to add ratings to my books table, where it would be in a range from 0-100, but I'm not sure how to add that here, all i could find was querying with ranges. I'm sure it's simple I'm just not there yet.
You don't need to specify the range of integer values in your migration file. The migration file is simply used to add the database column to store the rating. This is not the place to add validations.
You should use your Book model to specify a validation that ensures your ratings fall within a certain range. Something like this:
class Book < ActiveRecord::Base
validates :rating, :inclusion => { :in => 0..100 }
end
I would highly recommend reading the Rails guides on both migrations and validations.
Probably I'm too late with the answer. But it's possible to define validation on db level with Migration Validators project: https://github.com/vprokopchuk256/mv-core
As example, in your migration:
def change
change_table :books do |t|
t.integer :rating, inclusion: 0..100
end
end
and then in your model:
class Book < ActiveRecord::Base
enforce_migration_validations
end
As result your validation will be defined both in db ( as statement inside trigger or check constraint, depending on your db) and on your model
SQL ( PostgreSQL ):
=# insert into books(rating) values(10);
INSERT 0 1
=# insert into books(rating) values(200);
ERROR: new row for relation "books" violates check constraint "chk_mv_books_rating"
Rails console:
Book.new(title: 10).valid?
=> true
Book.new(title: 200).valid?
=> false
I was under the impression that with Rails you're not supposed to define any dependencies in the database, but rather just use your has_many and belongs_to stuff to define relationships. However, I'm going through the rails guide, and it has the following.
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.string :commenter
t.text :body
t.references :post
t.timestamps
end
add_index :comments, :post_id
end
end
I thought this wasn't okay...? I'm trying to do something like a comment field that creates a new instance each time you call the show method, but I think without these "references" and "add_index," it's not storing the post_id in the comment row.
All this migration does is create post_id and tells the database that it should index this column (improves performance)
t.references :post is basically the same as t.integer :post_id so, yes, it is storing the post_id in the comment. You'll still need to define your relationships in your models.
You are actually wrong on the philosophy.
Rails magic is good, only when backed at the DB level by actual foreign keys.
The docs clearly state this
Rails magic comes in, when you have correctly named your foreign keys, so that it can use the convention to figure out the associations.
What's wrong with expressing relationships within the ORM, that's where it's supposed to be done. I believe you are getting mixed up between db vendor specifics such as foreign key constraints and relationships.
class Comment < ActiveRecord::Base
attr_accessible :post, :post_id
belongs_to :post
end
class Post < ActiveRecord::Base
has_many :comments
end
class CommentsController < ApplicationController
def create
#comment = Comment.create(params[:comment]) # where params[:comment] = {post_id: 1, message: ''}
#post = comment.post
respond_with(#comment)
end
end
The problem is that I get this error:
ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: amenity_id
when I run this code:
task import_amenities: :environment do
agent = Mechanize.new
Kindergarten.find_all_by_public(false).each do |k|
p = agent.get(k.uri)
amenities = p.search("td td tr:nth-child(11) td:nth-child(2)").text.split(/(;|,) */)
amenities.each do |a|
am = Amenity.find_or_create_by_name!("#{a}")
k.update_attributes(amenity_id: am.id)
end
end
end
Kindergartens and Amenities are linked through a HABTM relation and are are defined as below:
kindergarten.rb
class Kindergarten < ActiveRecord::Base
attr_accessible :location, :name, :public, :uri, :address, :contact,
:phone, :url, :email, :description,
:password, :password_confirmation, :amenity_ids
has_and_belongs_to_many :amenities
end
amenity.rb
class Amenity < ActiveRecord::Base
attr_accessible :name, :kindergarten_ids
has_and_belongs_to_many :kindergartens
end
and here's the migration for the join table:
class CreateKindergartensAmenitiesJoinTable < ActiveRecord::Migration
def up
create_table :kindergartens_amenities, :id => false do |t|
t.integer :kindergarten_id
t.integer :amenity_id
end
end
end
The error is caused by this line in the rake task:
k.update_attributes(amenity_id: am.id)
Everything seems to work great in the console until I reach the mass assignment. And I think i am really messing something up here since I've never used before HABTM.
Any thoughts?
I couldn't sleep last night because of this bug but I finally found the solution.
there are a few issues in the code and the first one i noticed once i started digging and adding data in the db manually is that the join table is wrongfully named. Fix for that:
class RenameKindergartensAmenitiesTable < ActiveRecord::Migration
def up
rename_table :kindergartens_amenities, :amenities_kindergartens
end
end
apparently the habtm association is has to have stuff put alphabetically in title. source
Second problem is that I assumed that
k.amenity_id = am.id
would add an amenity_id / kindergarten_id for each amenity existing. In fact k.amenity_id does not mean anything (especially in the case of many ids). The solution that worked is this:
amenities.each do |a|
am = Amenity.find_or_create_by_name!("#{a}")
k.update_attributes(amenity_ids: k.amenity_ids.push(am.id))
end
I haven't modified the attr_accessible anywhere