Rails has_many:通过独特性

时间:2016-03-11 22:08:31

标签: ruby-on-rails

我以不同的方式提出这个问题,但删除它以试图更清晰。

我有一个文章模型。它有很多联系人,通过:: article_contacts。

我有一个联系模式。它有很多文章,通过:: article_contacts。

我需要的是每个Contact对象都是唯一的,但是能够与不同的文章相关联。我的上一个问题导致人们向我展示如何仅显示唯一的联系人,或验证联接模型,但这不是我需要的。

例如,我需要以下表格:

Article
id: 1, name: "Whatever", content: "Whatever"
id: 2, name: "Again, whatever", content: "Whateva"

Contact 
id: 1, email: "email@email.com"
id: 2, email: "secondemail@email.com"

ArticleContact
id: 1, article_id: 1, contact_id: 1
id: 2, article_id: 1, contact_id: 2
id: 3, article_id: 2, contact_id: 1

因此,当我在新操作中在我的文章控制器中构建关联并在创建操作中调用@ article.save时,我会获得新文章的插入,联系人的插入和article_relationship的插入。大。

但是,就第2条而言,如果我向联系表单添加相同的电子邮件,我不想使用同一封电子邮件创建另一个联系人。但我确实想要(正如你在上面的ArticleContact中看到的第三个ID)来创建。但每次调用@ article.save都会这样做。我尝试过first_or_initialize和<<进入集合,但它总是创建多次,如果我有验证,这意味着我无法创建ArticleContact关系,因为联系是唯一的。

我最终可能会联系到联系人,但我怀疑这会很长,所以我只是简单地在表单中输入一封电子邮件并让代码检查它是否是唯一的,如果是这样,只需创建使用现有ID的连接关系。

这一定比我想象的要容易,但我找不到一篇能在任何地方展示这篇文章的文章。

更新了每个请求的代码,但是,我还没有让代码只创建一个独特的联系人,并将关系与现有联系人联系起来。这就是我所遗漏的内容,因此这段代码只会告诉您我已经知道的内容,而不是如何达到我想要的内容:)。

articlecontroller:

def new
  @article = @business.articles.build
  authorize @business
  @article.attachments.build
  @article.contacts.build
end

def create
  @article = @business.articles.new(article_params)
  authorize @business

  respond_to do |format|
    if @article.save
      format.html { redirect_to business_article_path(@business, @article), notice: "Knowledge created." }
    else
      format.html { render 'new' }
    end
  end

end

模型具有标准has_many:thruogh并且属于。我可以展示它,但它们是正确的方式。 View只是构建联系人的标准simple_form:

  <%= f.simple_fields_for :contacts, class: "form-inline" do |contact| %>
    <%= contact.input :first_name, label: "Contact First Name" %>
    <%= contact.input :last_name, label: "Contact Last Name" %>
    <%= contact.input :email, label: "Contact Email" %>
  <% end %>

3 个答案:

答案 0 :(得分:1)

您应该强制执行唯一性,以防万一:

# contact.rb
class Contact
  ...
  validates_uniqueness_of :email
  ...
end

但是在你的控制器中你可以做到:

# articles_controller.rb
def create
  ...
  # we can rely on it's uniqueness
  contacts << Contact.find_or_create_by(email: param[:email)
  ...
end

或最适合您需求的任何东西。

希望这有帮助!

答案 1 :(得分:1)

使用范围为您的ArticleContact进行验证。

validates :article_id, unique {scope: :contact_id}

这将阻止您使用完全相同的ArticleContacts。

创建联系人时,请尝试:

contact = Contact.where(email: "e@mail.com:").first_or_create

in contact.rb

validates :email, uniqueness: true

答案 2 :(得分:0)

您可以在创建方法

中尝试此操作
verified_contacts = []

@article.contacts.each do |contact|
  existing_contact = Contact.find_by(email: contact.email)
  verified_contacts << (existing_contact || contact)
end

@article.contacts = verified_contacts