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
Related
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
I have Hanami models User and UserInfo that have has_one association.
Repositories look the following:
class UserInfoRepository < Hanami::Repository
end
class UserRepository < Hanami::Repository
associations do
has_one :user_info
end
end
Question: who can I join and load both tables with one query? (I am looking for something similar to Rails' includes).
So far I've tried
def users_with_info
users.join(:user_info)
end
It does the join, but does not select columns from user_infos table.
Thanks in advance.
When you fetch data via a Repository in Hanami the result set is mapped into entities.
By default the UserRepository will map to the User entity. I'm guessing that that entity does not have attributes for the columns from user_info.
What you need to do is create an Entity that can contain the data that you want to fetch from the database and then call .as(ThatEntityYouCreated) on the result set. E.g.,
def users_with_info
users.join(:user_info).map_to(UserWithInfo)
end
If you do not want to create an Entity and just want to get a plain hash, you can do this:
users.join(:user_info).map.to_a
However, I consider this to be a crutch. You should not return Hashes from your Repository methods.
I believe we faced this exact issue with a teammate of mine on one of our Hanami project, and this is how we solved it.
We basically bypassed Hanami repository, going straight to the underlying ROM relation, using ROM::Relation#wrap in order to get our User entity joined with the entity of interest.
Let met know if it helped you, or if you need more details. Cheers!
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.
I'm looking for a suggestion on how to set up two models, Teacher and Subject. A Teacher can have many Subjects, and a Subject can have many Teachers. Another thing to consider in the relationship between the two models is that a Teacher can create a Subject and add other Teachers to the Subject.
I think I'm solid on the basics of the set up for each model:
for teacher.rb:
has_many :subjects
for subject.rb:
has_many :teachers
and the teachers table should have a subject_id column and the subject table should have a teacher_id column.
What I'm not sure about is how to set up the views (and corresponding controller methods) to allow the addition of a Teacher to a Subject.
Any suggestions (or links to examples) are greatly appreciated. I haven't been able to find anything on this exact case.
current set up:
standard CRUD for a Student object
standard CRUD for a Project object
I'm likely missing something simple in how to tie these models together (other than the part of changing has_many to habtm) and getting records into the subjects_teachers table, and I still can't find a good example...
You need to build the relational table between them. It's impossible to have a many-many relationship without a rel table
First off though, it's a has_and_belongs_to_many :subjects and has_and_belongs_to_many :teachers (commonly referred to as habtm)
http://guides.rubyonrails.org/association_basics.html#the-has_and_belongs_to_many-association
run
rails g migration subjects_teachers
open up the migration:
create_table :subjects_teachers, :id => false do |t| # ID => FALSE = IMPORTANT
t.references :subject
t.references :teacher
# NO TIMESTAMPS
end
run
rake db:migrate and you should be set!
then
see these railscasts for setting up your controllers
http://railscasts.com/episodes/17-habtm-checkboxes
http://railscasts.com/episodes/47-two-many-to-many
I have two tables, users and groups. A user can belong to many groups. A group can have many users.
So I have created a have_and_belongs_to_many relationship between users and groups using a join table, groups_users. This all works as expected.
What I would also like to do is specify an ACTIVE group for each user. Were it not for the habtm relationship I have already defined, I would create a column “group_id” in users for the active group, and then I would define a one-to-many relationship between the models as follows:
class User < ActiveRecord::Base
belongs_to :group
end
class Group < ActiveRecord::Base
has_many :users
end
This didn’t work. I could not access group properties like “#user.group.name”. I suspect that I’m asking too much of Rails by specifying two relationships.
So I have three questions.
I could very easily understand if combining the two relationships confuses Active Record . Is that the case?
If so, how would you implement these relationships? Right now I’m just manually using the group_id, but that feels messy.
Regardless of whether I am using Active Record magic or manually setting the active group, it is possible for a user’s active group to be outside the group’s they belong to using the first habtm relationship. Any thoughts on how to implement this with the constraint that the active group must be a group that the user belongs to?
Thanks for any insights. I am a couple of weeks into the Rails learning curve and I think that getting to the bottom of this little problem will deepen my understanding of models and table relationships quite a bit.
Greg - I've done this before, similar to what as your proposing. I used a "primary_group" instead of "group" and set the foreign_key to be "primary_group_id" and the :class_name => 'Group'
I don't use has_and_belongs_to_many very often so I don't know if that would be causing an issue, but I don't think so - at least not with the user model. You don't have a #group method, so setting belongs_to should be OK. I don't know if you absolutely must have have a has_many :users method on the group, but you may not need it anyway. This will certainly cause a collision with the 'users' method that habtm creates. If you do need this, try has_many :primary_users and set the :foreign_key => :primary_group_id
Just some thoughts. You should be able to do what you're doing now, so not sure what's failing.