将表单文本输入的电子邮件列表保存到模型 email_list 属性(数组)

Saving a list of emails from a form-text input into Models email_list attribute (array)

我的目标是在使用新产品表单添加新产品时,提供一个输入,其中可以添加由 space 分隔的电子邮件列表。此字符串字段中的电子邮件列表将保存为 Product 模型的 email_list 数组属性中的电子邮件数组。这样每个产品都有很多电子邮件。 (稍后将向这些用户发送一封电子邮件以填写问卷,一旦用户填写完成,姓名将从该列表中删除并放入 completed_email_list 数组。

我对 rails 比较陌生,有几个关于实现它的问题。我正在使用 postgresql,据我所知,我不需要因此而将模型序列化为数组格式。以下是我迄今为止为实现这一目标所做的尝试。这些可能表明我对一切运作方式的思考存在根本性缺陷。

我的第一个想法是,我可以在我的控制器中创建动作,首先采用参数[:email].split 并将其直接保存到 email_list 属性中 (@product.email_list = params[:email].split。结果是 params[:email]总是nil这是为什么?(这是我的一个基本误解)(我把:email作为接受的参数)。

在花了很长时间试图解决这个问题之后,我尝试了以下似乎可行的方法,但我觉得这可能不是最好的方法(在下面的代码中),它涉及创建另一个属性名为 email 的字符串,然后将其拆分并保存在 email_list 数组中:

   @product.email_list = @product.email.split

实际实现它的最佳方法是什么?有人可以清除我对此的想法,我将不胜感激。

干杯

Products.new 查看

<%= simple_form_for @product do |f| %>
  <%= f.input :title, label:"Product title"  %>
  <%= f.input :description  %>
  <%= f.input :email %>
  <%= f.button :submit %>
<%end %>

产品控制器

class ProductsController < ApplicationController
  before_action :find_product, only: [:show, :edit, :update, :destroy]

  def index
    if params[:category].blank?
      @products= Product.all.order("created_at DESC")
    else
      @category_id=Category.find_by(name: params[:category]).id
      @products= Product.where(:category_id => @category_id).order("created_at DESC")
    end
  end

  def new
    @product=current_user.products.build
    @categories= Category.all.map{|c| [c.name, c.id]}
  end

  def show
  end

  def edit
    @categories= Category.all.map{|c| [c.name, c.id]}
  end

  def update
    @product.category_id = params[:category_id]

    if @product.update(product_params)
      redirect_to product_path(@product)
    else
      render 'new'
    end
  end

  def destroy
    @product.destroy
    redirect_to root_path
  end

  def create
    @product=current_user.products.build(product_params)
    @product.category_id = params[:category_id]
    @product.email_list = @product.email.split
    if @product.save
      redirect_to root_path
    else
      render 'new'
    end
  end

  private

  def product_params
    params.require(:product).permit(:title, :description, :category_id, :video, :thumbnail,:email, :email_list)
  end

  def find_product
    @product = Product.find(params[:id])
  end
end

我会说你拥有的东西非常好,除了你在 @product.email_list=@product.email.split 中做的额外舞蹈,这看起来很奇怪。

相反,我在表单中有一个 emails 参数,在模型中有一个 #emails= 方法(而不是 email#email=):

def emails=(val)
  self.email_list = val.split
end

或者,您可以在控制器中执行此操作,而不是使用上述方便的 #emails= 方法,类似于您处理 category_id:

的方式
@product = current_user.products.build(product_params)
@product.category_id = params[:category_id]
@product.email_list = product_params[:emails].split

因为您需要验证您的电子邮件并使其更清晰,我会创建一个 email table,使 Product table 接受 Email 属性并使用 cocoon gem 来获得一个带有多个电子邮件输入的动态嵌套表单。

1) 型号

class Product < ActiveRecord::Base
  has_many :emails, dependent: :destroy
  accepts_nested_attributes_for :emails, reject_if: :all_blank, allow_destroy: true
end

class Email < ActiveRecord::Base
  belong_to :product
  validates :address, presence: true
end

2) 控制器

class ProductsController < ApplicationController
  def new
    @product = current_user.products.build
  end

  def create
    @product = current_user.products.build(product_params)
    if @product.save
      redirect_to root_path
    else
      render 'new'
    end
  end

  private

  def product_params
    params.require(:project).permit(:title, :description, :category_id, :video, :thumbnail, emails_attributes: [:id, :address, :_destroy])
  end
end

3) 查看

<%= simple_form_for @product do |f| %>
  <%= f.input :title, label:"Product title"  %>
  <%= f.input :description  %>
  <%= f.association :category %>

  <div id="emails">
    <%= f.simple_fields_for :emails do |email| %>
      <%= render 'emails_fields', f: email %>
      <div class="links">
        <%= link_to_add_association 'add email', f, :emails %>
      </div>
    <%= end %>
  </div>

  <%= f.button :submit %>
<% end %>

在你的 _emails_fields 部分:

<div class="nested-fields">
  <%= f.input :address %>
  <%= link_to_remove_association "Remove email", f %>
</div>

然后设置 cocoon 的 gem 和 javascript 就可以了。

参考:https://github.com/nathanvda/cocoon

解决您原来的问题

@product.email_list = params[:email].split. It turns out that params[:email] is always nil

:email:product散列的子键,所以应该是:

@product.email_list = params[:product][:email].split

演示:

params = ActionController::Parameters.new(product: { email: "first@email.com last@email.com" })
params[:email] # => nil
params[:product][:email] # => "first@email.com last@email.com"