Save active record object without reference id - ruby-on-rails

I have the following migrations:
class CreateMothers < ActiveRecord::Migration[5.0]
def change
create_table :mothers do |t|
t.string :name
t.timestamps
end
end
end
and:
class CreateSons < ActiveRecord::Migration[5.0]
def change
create_table :sons do |t|
t.string :name
t.references :mother
t.timestamps
end
end
end
Whenever I try to save a Son object with the mother_id field blank, I get the error: "Mother must exist"
Is there a way to save this without the mother_id field?

In your Son model, just add the optional param to make it work:
class Son < ApplicationRecord
belongs_to :mother, optional: true
end
In default, rails set it to be true, so let use false instead, the detail was described here

Related

Rails uniqueness constraint on two column values in different models

I want to know the best way to have an uniqueness constraint enforced on two related model attributes in rails that are both no primary keys
class Parent > ApplicationRecord
has_many :children
:name
end
class Child > ApplicationRecord
:name
end
I want to enforce that (parent.name, child.name) is unique for every parent. e.g.
(parent1, child1) and (parent2, child1) is allowed
(parent1, child1) and (parent1, child1) is a violation
Ideally, I would enforce this in Postgres, however I have only seen the option to add uniqueness constraints on multiple columns of the same table.
Alternatively, I have written a custom validator for rails that does what I want, but this is cumbersome. There needs to be a better solution...
For completeness, here is the constraints validator which requires one to add a children function to a model returning the list of children.
class NamePairValidator < ActiveModel::Validator
def validate(record)
record.children.values.each do |model_children|
names = model_children.to_a.collect {|model| model.name}
if (names.select{|name| names.count(name) > 1 }.size > 0)
record.errors[:name] << 'Path leading to this resource has no unique name'
end
end
end
end
(in Parent.rb)
def children
{children: :children}
end
Migrations:
class CreateDomains < ActiveRecord::Migration[5.0]
def change
create_table :domains do |t|
t.string :name
t.string :domain_type
t.timestamps
end
end
end
class CreateSubjects < ActiveRecord::Migration[5.0]
def change
create_table :subjects do |t|
t.string :name
t.string :subject_type
t.timestamps
end
end
end
class CreateJoinTableDomainSubject < ActiveRecord::Migration[5.0]
def change
create_join_table :domains, :subjects do |t|
t.index [:domain_id, :subject_id]
t.index [:subject_id, :domain_id]
end
end
end
I just used similar one in my code
validates :child_name, uniqueness: { scope: :parent_id }
More..
(i) https://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of
(ii) Validate uniqueness of multiple columns
Insipered by the-has-many-through-association of the official doc of ruby on rails:
class CreateAppointments < ActiveRecord::Migration[5.0]
def change
create_table :domains do |t|
t.string :name, null: false
t.string :domain_type
t.timestamps
end
create_table :subjects do |t|
t.string :name, null: false
t.string :subject_type
t.timestamps
end
create_table :fields do |t|
t.belongs_to :domain, index: true
t.belongs_to :subject, index: true
t.timestamps
end
end
end
Note
I took the initative to rename your model JoinTableDomainSubject by Field to be more readable.
I also force name field not be nil to check uniqueness.
(adding null: false in migrations files and validates :name, presence: true in both models)
Now the dedicated classes:
class Subject < ApplicationRecord
has_many :fields
has_many :domains, through: :fields
validates :name, presence: true
end
class Domain < ApplicationRecord
has_many :fields
has_many :subjects, through: :fields
validates :name, presence: true
end
class Field < ApplicationRecord
belongs_to :domain
belongs_to :subject
validate :domain_and_subject_names_uniqueness
private
def domain_and_subject_names_uniqueness
if class.includes(:domain, subject)
.where(domain: { name: domain.name }, subject: { name: subject.name })
.exists?
errors.add :field, 'duplicity on names'
end
end
end
Since the models are associated, I can use Field.first.domain to access Domain model of a given Field and vice versa.

PG::Error: ERROR: column tutorials.tutorialcategory_id does not exist

I have two models 'Tutorial' and 'Tutorialcategory'
class Tutorialcategory < ActiveRecord::Base
has_many :tutorials
class Tutorial < ActiveRecord::Base
belongs_to :tutorialcategory
Tutorials are associated with multiple categories like html,rubyonrails where html and ruby on rails are tutorialcategories
followings are migrations
class CreateTutorials < ActiveRecord::Migration
def change
create_table :tutorials,force: true do |t|
t.string :title
t.text :body
t.integer :rating
t.string :videoid
t.belongs_to :tutorialcategory
t.timestamps
end
end
end
class CreateTutorialcategories < ActiveRecord::Migration
def change
create_table :tutorialcategories do |t|
t.string :title
t.timestamps null:false
end
end
end
All tutorials are listing properly on index page but when I see category page it gives me following error
PG::Error: ERROR: column tutorials.tutorialcategory_id does not exist
I have no idea why you named your model Tutorialcategory instead of TutorialCategory which follow Rails naming convention and make it easier to understand.
Firstly, rollback your db one step
rake db:rollback
Change your migration file to:
class CreateTutorials < ActiveRecord::Migration
def change
create_table :tutorials,force: true do |t|
t.string :title
t.text :body
t.integer :rating
t.string :videoid
t.belongs_to :tutorial_category, index: true
t.timestamps
end
end
end
class CreateTutorialCategories < ActiveRecord::Migration
def change
create_table :tutorial_categories do |t|
t.string :title
t.timestamps null:false
end
end
end
Run the migration again and edit your model to match with new schema.
class TutorialCategory < ActiveRecord::Base
has_many :tutorials
class Tutorial < ActiveRecord::Base
belongs_to :tutorial_category

ActiveRecord: find appropriate translation

I have models:
Category:
class Category < ActiveRecord::Base
has_many :entities, as: :resourcable
end
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.string :name
t.text :short_descr
t.text :full_descr
t.timestamps
end
end
end
Language:
class Language < ActiveRecord::Base
has_many :entities, as: :resourcable, dependent: :destroy
validates :code, uniqueness: true
end
class CreateLanguages < ActiveRecord::Migration
def change
create_table :languages do |t|
t.string :name
t.string :code
t.timestamps
end
end
end
And Entity:
class Entity < ActiveRecord::Base
belongs_to :language
belongs_to :resourcable, polymorphic: true
end
class CreateEntities < ActiveRecord::Migration
def change
create_table :entities do |t|
t.integer :language_id
t.string :name
t.text :short_descr
t.text :full_descr
t.references :resourcable, polymorphic: true
t.timestamps
end
end
end
In Categories there are default values for fields (short_descr, full_descr), In Entities there are translations for this fields. I need to render as json all Categories with appropriate translations: at first, I need to take Language with appropriate code (for example ru), next, I need to find all language Entities for this language, next, if Entity have filled short_descr and full_descr I need to render Category with this values, else I need to render the Category with default values (this values in Categories table). How to do this? I prefer ActiveRecord buy consider pure SQL.
EDITED
Now I'm trying to use gem 'squeel':
Language.joins{entities.category}.
select{coalesce(entities.short_descr, categories.short_descr)}.
where{languages.code == 'en'}
but it doesn't work (undefined methodshort_descr' for nil:NilClass`). There is the problem?
Entity.joins(:language, :category).
select('categories.*, coalesce(entities.short_descr, categories.short_descr) as short_descr,
coalesce(entities.full_descr, categories.full_descr) as full_descr').
where('languages.code = ?', 'en')

Setting columns to references in rails 4

In my web app, I have nodes and links. A link has two nodes. One node is a source node, and the other node is a target node. Basically, I want source and target columns in the database that hold references to nodes. I am trying to figure out how to implement this.
Here is the migration for the nodes model:
class CreateNodes < ActiveRecord::Migration
def change
create_table :nodes do |t|
t.string :name
t.integer :group
t.references :link, index: true
t.timestamps
end
end
end
Here is the node model:
class Nodes < ActiveRecord::Base
belongs_to :link
end
I am trying to figure out how to set up the migration for the links model. Here is what I have so far:
class CreateLinks < ActiveRecord::Migration
def change
create_table :links do |t|
t.integer :value
t.boolean :checked
t.timestamps
end
end
end
Here is what I have in my model:
class Links < ActiveRecord::Base
has_many :nodes
end
Would the correct migration look like this?
class CreateLinks < ActiveRecord::Migration
def change
create_table :links do |t|
t.integer :value
t.boolean :checked
t.references :source
t. references :target
t.timestamps
end
end
end
t.references :smith is basically a shortcut for t.integer :smth_id so if your Nodes belong to Links, then yes that construction seems correct.
not sure where your links#source and links#target point to though.

Rails 2: joint multi table

Sorry, i'am newbie
I have database:
Migrate
-Mst_group tble
class CreateMstGroups < ActiveRecord::Migration
def self.up
create_table :mst_groups do |t|
t.string :group_name
end
end
end
-Mst_japan
class CreateMstJapans < ActiveRecord::Migration
def self.up
create_table :mst_japans do |t|
t.string :name_level
end
end
end
-Tbl_user
class CreateTblUsers < ActiveRecord::Migration
def self.up
create_table :tbl_users do |t|
t.string :login_name, :null =>false,:limit =>15
t.string :password,:null =>false,:limit =>50
t.string :full_name,:null =>false
t.string :full_name_kana
t.string :email,:null =>false
t.string :tel,:null =>false,:limit =>15
t.date :birthday,:null =>false
t.references :mst_groups
end
end
end
-Tbl_detail_user_japan
class CreateTblDetailUserJapans < ActiveRecord::Migration
def self.up
create_table :tbl_detail_user_japans do |t|
t.date :start_date
t.date :end_date
t.integer :total
t.references :tbl_users
t.references :mst_japans
end
end
end
Model
class MstGroup < ActiveRecord::Base
has_many :tbl_users
end
class MstJapan < ActiveRecord::Base
has_many :tbl_detail_user_japans
end
class TblUser < ActiveRecord::Base
belongs_to :mst_group
has_one :tbl_detail_user_japan
end
class TblDetailUserJapan < ActiveRecord::Base
belongs_to :tbl_user
belongs_to :mst_japan
end
Controller
def index
#user= ???????
end
How to write command select : login_name, full_name, full_name_kana, email, tel, group_name, name_lever, start_date, end_date, total in controller
It depends on how you want to retrieve the User object. You need to tell Rails how to find the TblUser object. If, for example, the user ID is known, let's say in a variable called 'id' then you would do:
def index
#user=TblUser.find(id)
end
It depends on your application logic how Rails would know which user you need. You may need an input from the user in case of log in, etc.
(Typically in Rails you would call the table 'Users', by convention tables and classes have the same name and then you wouldn't need to call the class TblUser)
That is all you need in the controller, you don't need to tell it which fields you want.
Then in the View you can access all the fields:
Fields on TblUser, example:
<%= #user.email %>
You can access the fields from related objects through the relations, example:
<%= #user.mst_group.group_name %>
Hope that helps to get you started.

Resources