I have a local user model which uses activerecord. The user has an email field. I also have an activeresource model called tasks which has a created_by field which stores the submitting users email address. I'd like to link the two but I'm struggling with the right syntax or even whether it's possible.
The main branch of ActiveResource doesn't even seem to support foreign key. I found an alternative branch but still couldn't get anything working.
class User < ActiveRecord::Base
has_many :tasks
end
class Task < ActiveResource::Base
belongs_to :user
schema do
string 'created_by' #email
# other fields
end
end
Your code should work fine given that you have a user_id
attribute on the Task
to act as the foreign key, or you can specify the foreign key in the association on User
model as follows:
class User < ActiveRecord::Base
has_many :tasks, foreign_key: "uid"
end
Now the problem is, you can't use belongs_to
on ActiveResource
so unless you need to retrieve the user
from an instance of the Task
class, you can just remove it and the other side of the relation will still work, however, if you need to retrieve the user
then you'd have to either implement your own finder method as follows:
class Task < ActiveResource::Base
schema do
string 'created_by' #email
# other fields
end
def user
@user ||= User.find self.user_id # use the attribute name that represents the foreign key
end
def user=(user)
@user = user
self.update_attribute(:user_id, user.id)
end
end
This will basically behave the same as you would expect on an ActiveRecord
model, however this can be tiresome if you have multiple associations so you can instead extend the ActiveResource
module to add belongs_to
as follows:
module BelongsToActiveResource
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def belongs_to( name, options = {} )
class_eval %(
def #{name}
@#{name} ||= name.to_s.classify.find( name.id )
end
def #{name}=(obj)
@#{name} ||= obj
self.update_attribute((name.to_s + "_id").to_sym, @#{name}.id
end
)
end
end
end
ActiveResource::Base.class_eval { include BelongsToActiveResource }
This will allow you to use belongs_to on any ActiveResource
model.
P.S.: the above solution was inspired by https://stackoverflow.com/a/8844932/3770684
You can't, but you can fake it by implementing accessor methods yourself.
class User < ActiveRecord::Base
#has_many :tasks
def tasks
Task.find(:all, params: {created_by: email})
end
end
class Task < ActiveResource::Base
#belongs_to :user
def user
User.where(email: created_by).first
end
schema do
string 'created_by' #email
# other fields
end
end
This will let you write code as if your objects were associated (i.e. User.first.tasks.length
). However, they aren't actually joined. That means calling User.first.tasks
is going to hit the database, then make an additional HTTP request to retrieve the Tasks. Depending on how your code is structured, you could run into unexpected performance issues.
Also, you can't run a single query to get a User and all associated Tasks (since it's two separate data stores), and you can't do fancy stuff like User.joins(:tasks).where({tasks: field_1: true})
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With