Creating has_many relationships in ActiveRecord without :primary_key - ruby

I'm working with an older version of Rails and ActiveRecord that does not have the :primary_key option in has_many relationships of more recent ActiveRecord versions and unfortunately I don't get to control when we upgrade. Is there any way to hack this solution via :conditions or :finder_sql options?

It should be possible using :finder_sql e.g.
has_many :foobars, :finder_sql => 'select * from table where foreign_key = #{primary_key}'
Note the use of single quotes around the query so that #{primary_key} is not expanded at the time when the association is declared.

Related

Ruby On Rails - new migration and model change causing migration failure

I've created a new migration to add a new table. Lets call it
new_items which creates a new table.
in the migration, i've specified that the relationship with another table
t.belongs_to :parent
In my model,
class NewItem < ApplicationRecord
belongs_to :parent
class Parent < ApplicationRecord
has_many :new_items, :dependent => :destroy
So when I run all migration from scratch, there is a failure on an older migration
"could not find table 'new_items'"
in the failed migration, this is the line that where the problem lies
def up
Parent.where(name: "TestName").destroy_all
end
there is something wrong with my Parent model, as when i remove this following line it runs to completion
has_many :new_items, :dependent => :destroy
I know the issue is with the relationship between Parent and NewItem, but not sure how its best fixed
I can kinda see why its happening, but not sure how to resolve it while still keeping the relationship between the tables
Whenever using your ActiveRecord models in migrations, it is wise to define them within these migrations, so any changes to your models in the future won't break old migrations.
class Parent < ApplicationRecord; end
or in a nicer way, if your class does not need to do anything
Parent = Class.new(ApplicationRecord)
added inside your migration class should fix your issue.
Side note: if you simply want to delete all the records from parents table, it would be better to call to call Parent.delete_all in your migration. This would also solve the issue, but adding models to migrations is good practice.
You should not use ActiveRecord models in the migration. ActiveRecord doesn't like when Ruby class and schema doesn't match. And it can happens if multiple migration need to be run.
I suggest to only use SQL queries in migration.
def up
execute <<-SQL
DELETE FROM parent WHERE name = "TestName";
SQL
end

Hanami repository delete/update operations using joins

I'm having some trouble doing delete/update operations using joins on a repository.
I have Libraries that belong to Users and have many Books, like so:
class LibraryRepository < Hanami::Repository
associations do
belongs_to: user
has_many :books
end
class BookRepository < Hanami::Repository
associations do
belongs_to :library
end
Now what I want to delete a book entry, but only if it belongs to the user library. I was trying to do that using the following query:
books.join(libraries).where(libraries[:user_id] => user_id).where(id: id).delete
But I get the following error:
Sequel::Error: Need multiple FROM tables if updating/deleting a dataset with JOINs
Any suggestions into how I could do such a query?
I think Hanami do not support multiple from, but postgresql does
books.dataset.from(:books, :libraries).where(Sequel[:libraries][:user_id] => user_id, Sequel[:id] => id).delete

How do I declare model attributes in Rails 4?

I am trying to understand Rails and I dont understand how I declare the model attributes correctly. For now my user class is looking like this:
class User < ActiveRecord::Base
has_many :users # Friends
end
By Googling I have understand that before Rails 4 one could determine attributes with the attr_accessible, like this:
attr_accessible :firstname, :lastname, :age, :sex
But this seems to be deprecated, how can I do that same thing in Rails 4?
has_many :users is not a model attribute, its model association. It means model User can have many User objects, which is incorrect. (also does not make sense even literally)
What attr_accessible does?
Specifies a white list of model attributes that can be set via
mass-assignmen
To add attributes to a model, you need to generate migrations.
Example, lets add name attribute to users:
rails generate migration AddNameToUsers #creates a migration file to add `name` column to `users` table
followed by:
rake db:migrate # executes migration file creating `name` column in `users` table
Now you can access these attributes simply as:
user = User.new
user.name
Again, if you want to mass-assign this attribute at some point of your code, you will need to specify this in your class with attr_accessible, as in your original example.

Sinatra with existing database (that doesn't abide by naming conventions)

I have an existing legacy Firebird database with nonstandard table and field names.
I would like to write a Sinatra app that can access it and display information. I've seen stuff like dm-is-reflective that appears to work when a database has proper naming conventions, but how do I use DataMapper (or ActiveRecord whichever is the easiest) to access those tables?
For example, assuming I had these two tables:
Bookshelfs
shelf_id: integer
level: integer
created: timestamp
Book
id: integer
id_of_shelf: integer
title: string
pages: integer
Something like with odd naming conventions that don't follow any set pattern and where one table's record might "own" multiple entries in another table even though there is not foreign_key assigned.
How would you set up datamapper (or activerecord) to communicate with it?
Look in to this gem to get setup with ActiveRecord on Sinatra:
https://github.com/bmizerany/sinatra-activerecord
As for how to define the relations, activerecord can do this easily.
class Book < ActiveRecord::Base
belongs_to :bookshelf, :class_name => 'Bookshelf', :foreign_key => 'id_of_shelf'
end
class Bookshelf < ActiveRecord::Base
has_many :books, :class_name => 'Book', :foreign_key => 'id_of_shelf'
end
Assuming you figured out how to connect to your legacy database using ActiveRecord's Firebird adapter, the next thing I would do is define a view on top of each table, e.g.
CREATE VIEW books AS SELECT * FROM Book;
CREATE VIEW bookshelves AS SELECT * FROM Bookshelfs;
This way you can simply define models Book and Bookshelf in ActiveRecord as per usual and it will find everything in the right place inside the database.

Rails has_many association results in a "no such column" error

I am following the guide at http://guides.rubyonrails.org/association_basics.html
and I have created
class Customer < ActiveRecord::Base
has_many :orders, :dependent => :destroy
end
class Order < ActiveRecord::Base
belongs_to :customer
end
but executing #order = #customer.orders.create() results in
unknown attribute: customer_id
Do you know why does this error occurs? And more importantly Is there a hidden reason for all the guides for has_many to drive you insane with showing this example, but non of them to be actually working :)
You need to add customer_id column to orders table.
For that you have to run the migration -
rails g migration add_customer_id_to_orders customer_id:integer
then
rake db:migrate
You're going to have to add a customer_id column to your orders table.
ActiveRecord doesn't know which customer to fetch for the relating order.
Try rails g migration AddCustomerIdToOrders customer_id:integer (don't forget db:migrate).
Sounds like you forgot to run your migrations. From the console and within the root directory of your rails project, run rake db:migrate to ensure rails has generated all the backing tables and columns for your associations and models.

Resources