I have a family_tree
and someone can add their relatives to the tree.
So what happens is there is a membership
record created for each family_tree entry.
However, if a Son
adds a Dad
, we should be able to update the family tree of the Dad to add the "Son" to the tree in the view. What's the best Rails way to approach this? I know Rails does a lot of translations natively, and pluralizations, etc. Anyway for me to leverage that for what I want to do?
Also, what is the class/module that handles that stuff again? ActiveSupport?
This is my User
model:
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# email :string(255) default(""), not null
# encrypted_password :string(255) default(""), not null
# reset_password_token :string(255)
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0), not null
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string(255)
# last_sign_in_ip :string(255)
# created_at :datetime
# updated_at :datetime
# name :string(255)
# confirmation_token :string(255)
# confirmed_at :datetime
# confirmation_sent_at :datetime
# unconfirmed_email :string(255)
# invitation_relation :string(255)
# avatar :string(255)
#
class User < ActiveRecord::Base
has_one :family_tree, dependent: :destroy
has_many :memberships, dependent: :destroy
has_many :nodes, dependent: :destroy
has_many :participants, dependent: :destroy
end
FamilyTree.rb
# == Schema Information
#
# Table name: family_trees
#
# id :integer not null, primary key
# name :string(255)
# user_id :integer
# created_at :datetime
# updated_at :datetime
#
class FamilyTree < ActiveRecord::Base
belongs_to :user
has_many :memberships, dependent: :destroy
has_many :members, through: :memberships, source: :user, dependent: :destroy
has_many :nodes, dependent: :destroy
end
Membership.rb
:
# == Schema Information
#
# Table name: memberships
#
# id :integer not null, primary key
# family_tree_id :integer
# user_id :integer
# created_at :datetime
# updated_at :datetime
# relation :string(255)
#
class Membership < ActiveRecord::Base
belongs_to :family_tree
belongs_to :user
end
Node.rb
# == Schema Information
#
# Table name: nodes
#
# id :integer not null, primary key
# name :string(255)
# family_tree_id :integer
# user_id :integer
# media_id :integer
# media_type :string(255)
# created_at :datetime
# updated_at :datetime
# circa :datetime
# is_comment :boolean
#
class Node < ActiveRecord::Base
belongs_to :family_tree
belongs_to :user
belongs_to :media, polymorphic: true, dependent: :destroy
has_many :comments, dependent: :destroy
has_many :node_comments, dependent: :destroy
end
My _tree.html.erb
looks like this (truncated for brevity):
<li class="tree-item-name"><a href="#">Great Grandparents</a>
<ul>
<li><% if relative.humanize == "Great Grandfather" || relative.humanize == "Great Grandmother" %>
<%= link_to image_tag(membership.user.avatar.url, size: "48x48", :class => "img-circle") , family_tree_path(membership.user.family_tree), :target => '_blank' %>
<%= link_to membership.user.name, family_tree_path(membership.user.family_tree), :target => '_blank'%>
<% else %>
None added yet, add them <%= link_to 'here', "#" , class: 'btn invite popupbox','data-popup' => 'invite_friend' %>
<% end %>
</li>
</ul>
</li>
<li class="tree-item-name"><a href="#">Grandparents</a>
<ul>
<li><% if relative.humanize == "Grandfather" || relative.humanize == "Grandmother" %>
<%= link_to image_tag(membership.user.avatar.url, size: "48x48", :class => "img-circle") , family_tree_path(membership.user.family_tree), :target => '_blank' %>
<%= link_to membership.user.name, family_tree_path(membership.user.family_tree), :target => '_blank' %>
<% else %>
None added yet, add them <%= link_to 'here', "#" , class: 'btn invite popupbox','data-popup' => 'invite_friend' %>
<% end %>
</li>
</ul>
</li>
I would use the same relations you defined in the question, except this part:
class Membership < ActiveRecord::Base
belongs_to :family_tree
belongs_to :user_one, class_name: 'User'
belongs_to :user_two, class_name: 'User' # I actually have no idea how to call them!
belongs_to :relation # to hold values likes 'Son', 'Dad', etc.
# The model Relation would be as simple as a name and internal reference, nothing else.
# (internal_reference is here to solve the translation problems and other stuff you will understand with the following code)
With a callback after_create
to reverse the membership created:
def create_reverse_membership
user_one_is_female = user_one.gender == 'female'
user_two_is_female = user_two.gender == 'female'
son_or_daughter = user_one_is_female ? :daughter : :son
father_or_mother = user_two_is_female ? :mother : :father
case relation.internal_reference.to_sym
when :son
relation = Relation.find_by_internal_reference(father_or_mother)
membership = Membership.where(relation_id: relation.id, user_one: user_two.id, user_two: user_one.id).first
if membership.present?
# This means the reverse membership already exists, do not call Membership.create here because it would cause and endless loop with the callback
else
membership = Membership.create(relation_id: relation.id, user_one: user_two, user_two: user_one)
end
when :father
# almost same logic but with `son_or_daughter`
when :mother
else
end
end
English not being my native language, this code probably lacks of consistency (coherence, logic).
Hope this helps!
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