我如何优雅地处理与Rails翻译的双面关系?

时间:2014-10-09 21:04:09

标签: ruby-on-rails activerecord ruby-on-rails-4

我有一个family_tree,有人可以将他们的亲戚添加到树中。

所以会发生的事情是为每个family_tree条目创建了membership条记录。

但是,如果Son添加了Dad,我们应该能够更新爸爸的家谱,将“Son”添加到视图中的树中。什么是最好的Rails方法来解决这个问题?我知道Rails本身会做很多翻译,并且会有多元化等等。无论如何,我可以利用它来做我想做的事情吗?

另外,再次处理这些东西的类/模块是什么?的ActiveSupport?

这是我的User型号:

# == 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

我的_tree.html.erb看起来像这样(为简洁而截断):

      <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>

1 个答案:

答案 0 :(得分:2)

我会使用你在问题中定义的相同关系,除了这一部分:

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)

使用回调after_create来撤销创建的成员资格:

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

英语不是我的母语,这段代码可能缺乏一致性(连贯性,逻辑性)。

希望这有帮助!