I've the following two models:
class Dispute < ApplicationRecord
belongs_to :accuser, class_name: 'User', optional: true
belongs_to :defendant, class_name: 'User', optional: true
end
class User < ApplicationRecord
end
Here's the migration for Dispute:
class CreateDisputes < ActiveRecord::Migration[5.0]
def change
create_table :disputes do |t|
t.references :accuser
t.references :defendant
end
end
end
This is how they behave in Rails:
Dispute.first.accuser
# => <# User>
Dispute.first.defendant
# => <# User>
In Sequel, I'm supposed to use many_to_one, but does that mean that Sequel User model should have a corresponding one_to_many? Can't seem to get it to work.
This should work:
Sequel.migration do
change do
create_table(:disputes) do
primary_key :id
foreign_key :accuser_id, :users
foreign_key :defendant_id, :users
end
end
end
class Dispute < Sequel::Model
many_to_one :accuser, :class=>:User
many_to_one :defendant, :class=>:User
end
Related
I'm building a sinatra app with Active record. The idea is to essentially have a custom email app. Here I have the models User and Message. A User has_many :messages and a Message belongs_to :user. This may be where I have the issue. I also have it set up for a Message belongs_to :user and has_many :users.
here are the models
Now when I create a message in the action controller I am attempting to use the shove methods to put the new message in a user's messages array. If I attempt to "share" this message with multiple users at once with all the user's id's in params( #user = User.find(id) and then user.messages << #new_message) the last user will have the message stored in it's .messages array. However only the last one to be iterated.
class Message < ActiveRecord::Base
belongs_to :user
has_many :users
end
class User < ActiveRecord::Base
validates :username, presence: true, uniqueness: true
has_secure_password
has_many :messages
end
The idea is the writer "owns" the message but can share it with many users. Here are the tables
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :username
t.string :email
t.string :password_digest
end
end
end
class CreateMessages < ActiveRecord::Migration
def change
create_table :messages do |t|
t.string :message
t.string :author
t.integer :user_id
t.integer :user_ids
t.integer :share_id
t.string :title
t.timestamps
end
end
end
# action controller
new_params = {}
new_params[:message] = params["message"]
new_params[:title] = params["title"]
new_params[:author] = params["author"]
new_params[:user_id] = params["user_id"]
#message = Message.create(new_params)
# #share = Share.create
# #message.share_id = #share.id
response.map do |x|
x.messages << #message
x.save!
end
#all = User.all
#user = User.find_by(username: #message.author)
erb :"/user/sent"
I am fairly sure this is because my associations are not set up properly.
You need to have has-and-belongs-to-many relationship between users and messages to implement sharing multiple messages to multiple users. Create an additional record, e.g. MessageShare and do has many to it from both sides:
class MessageShare < ActiveRecord::Base
belongs_to :user
belongs_to :message
end
class Message < ActiveRecord::Base
has_many :message_shares
end
class User < ActiveRecord::Base
has_many :message_shares
end
message_shares table should have user_id and message_id integer columns.
I have my resources:
resources :flows do
resources :fmodules
end
the new method in fmodules controller:
# /flows/1/fmodules/new
def new
#flow = Flow.find(params[:flow_id])
#fmodule = #flow.fmodules.build
end
the models:
class Flow < ApplicationRecord
has_many :fmodules, dependent: :destroy
validates :code, presence: true, length: { maximum: 5 }
validates :name, presence: true
end
class Fmodule < ApplicationRecord
belongs_to :flow
end
When i try to go at /flows/1/fmodules/new ruby says unknown attribute 'flow_id' for Fmodule.
I dont know what is wrong
Here is the migration of Fmodel in addition
class CreateFmodules < ActiveRecord::Migration[5.1]
def change
create_table :fmodules do |t|
t.string :code
t.string :name
t.string :f_code
t.timestamps
end
add_foreign_key :fmodules, :flows, column: :f_code
end
end
So, the problem is that you don't have a flow_id in your fmodules table. In rails, by convention the foreign key is build automatically inferring column name from an argument you pass to belongs_to. That's why rails think that foreign key for flows table is flow_id and it raises exception not finding it. You can overwrite the default with foreign_key option like the following
class Fmodule < ApplicationRecord
belongs_to :flow, foreign_key: : f_code
end
I'm creating a second version of my app using using the following pattern:
class List < ActiveRecord::Base
has_many :listable_items
has_many :lists, through: :listable_items, source: :listable, source_type: 'List'
end
class ListableItem < ActiveRecord::Base
belongs_to :list
belongs_to :listable, polymorphic: true
end
module V2
class List < List
has_many :listable_items
has_many :lists, through: :listable_items, source: :listable, source_type: 'V2::List'
self.inheritance_column = :_non_existing_column
end
end
Module V2
class ListableItem < ListableItem
belongs_to :list, class_name: "V2::List"
belongs_to :listable, polymorphic: true
end
end
list = V2::List.find_by(slug: "people")
=> #<V2::List:0x007fd6e9007f18 id: 97, title: "People"....>
list.listable_items
=> [#<V2::ListableItem:0x007fd6e6497ec8 id: 2633, list_id: 97, listable_id: 100, listable_type: "List",....]
list.listable_items.first.listable
=> #<List:0x007fd6e4185868 id: 100,...>
I assume this is happening because of the class definition in the listable_type column of ListableItems. Is there a way to have it refer to the V2 version of the model instead of the one defined in the db column when I call the associated record?
adding
def listable_type
"V2::" + super
end
to the ListableItem class didn't change the class of the called listable.
The solution was to over-write the listable method, not the listable_type method. There may very well be a better way to do this, but this way worked for me.
Module V2
class ListableItem < ListableItem
belongs_to :list, class_name: "V2::List"
belongs_to :listable, polymorphic: true
def listable
("V2::" + listable_type).constantize.find(listable_id)
end
end
end
In my model an Item is created by a User and can be purchased by many Users, and a User can purchase many Items.
User, Item, and Purchase are defined, using AcvtiveRecord with superfluous details snipped for brevity as follows:
class User < ActiveRecord::Base
# various other fields
has_many :items, :foreign_key => :creator_id
has_many :purchased_items, :through => :purchases, :source => :item
end
class Item < ActiveRecord::Base
# various other fields
belongs_to :creator, :class_name => 'User'
has_many :buyers, :through => :purchases, :source => :user
end
class Purchase < ActiveRecord::Base
belongs_to :item
belongs_to :user
# various other fields
end
and an rspec test also snipped as follows:
describe "user purchasing" do
it "should allow a user to purchase an item" do
a_purchase = Purchase.create!(:item => #item, # set up in `before :each`
:user => #user # set up in `before :each`
)
a_purchase.should_not eq(nil) # passes
#item.buyers.should include #user # fails
#user.purchased_items.should include #item # fails
end
end
This results in
1) Purchase user purchasing should allow a user to purchase an item
Failure/Error: #item.buyers.should include #user
ActiveRecord::HasManyThroughAssociationNotFoundError:
Could not find the association :purchases in model Item
Likewise if I swap around #file_item.buyers.should include #user and #user.purchased_items.should include #item I get the equivalent
1) Purchase user purchasing should allow a user to purchase an item
Failure/Error: #user.purchased_items.should include #item
ActiveRecord::HasManyThroughAssociationNotFoundError:
Could not find the association :purchases in model User
My migration looks like
create_table :users do |t|
# various fields
end
create_table :items do |t|
t.integer :creator_id # file belongs_to creator, user has_many items
# various fields
end
create_table :purchases do |t|
t.integer :user_id
t.integer :item_id
# various fields
end
What have I done wrong?
You have to specify the following.
class User < ActiveRecord::Base
has_many :purchases
has_many :items, :foreign_key => :creator_id
has_many :purchased_items, :through => :purchases, :source => :item
end
class Item < ActiveRecord::Base
# various other fields
has_many :purchases
belongs_to :creator, :class_name => 'User'
has_many :buyers, :through => :purchases, :source => :user
end
Only when you specify
has_many :purchases
the model will be able to identify the association.
I have A number of models (Article, Video, Photo)
Now I am trying to create a related_to association, such that
An article can have many other articles, videos and photos related to it. As can videos and photos.
Heres what I have tried:
module ActsAsRelatable
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def acts_as_relatable
has_many :related_items, :as => :related
has_many :source_items, :as => :source, :class_name => 'RelatedItem'
end
end
end
class RelatedItem < ActiveRecord::Base
belongs_to :source, :polymorphic => true
belongs_to :related, :polymorphic => true
end
Then I have added acts_as_relatable to my three models (Article, Video, Photo) and included the module in ActiveRecord::Base
When trying in ./script/console I get it to add the related items and the ids work correctly however the source_type and related_type are always the same (the object that related_items was called from) I want the related_item to be the other model name.
Any ideas anyone?
I would use the has many polymorphs plugin since it supports double sided polymorphism you can do something like this:
class Relating < ActiveRecord::Base
belongs_to :owner, :polymorphic => true
belongs_to :relative, :polymorphic => true
acts_as_double_polymorphic_join(
:owners => [:articles, :videos, :photos],
:relatives => [:articles, :videos, :photos]
)
end
and don't forget the db migration:
class CreateRelatings < ActiveRecord::Migration
def self.up
create_table :relating do |t|
t.references :owner, :polymorphic => true
t.references :relative, :polymorphic => true
end
end
def self.down
drop_table :relatings
end
end
I don't know if "Relating" is a good name, but you get the idea. Now an article, video and photo can be related to another article, video or photo.