我正在尝试在我的项目中设置一个多选框,它将输出到sql表中的一个字符串字段中。到目前为止,我已经想到了<%f.select%>使用多个设置为true尝试传递数组而不是字符串,这对我的项目不起作用(过去这是一个文本字段,但现在需要只允许选择预设值,它是在现场项目,所以没有剧烈的变化)。我发现做这样的事情
@keywords = params['keywords']['keywords'].join(', ')
会解决我的问题,但我不知道如何在我的控制器中实现它。
我目前在视图中选择的代码片段是:
<%= f.select :keywords, ['kw1', 'kw2', 'kw3', 'kw4', 'kw5'], {}, { :multiple => true, :size => 10, :class => 'form-control' } %>
来自控制器的用于创建新文章的代码段目前非常基本:
@article = Article.new
“keywords”是文章表中的字符串字段。
编辑:这是整个控制器:
class ArticlesController < ApplicationController
PRIORITY_COUNTRIES = %w[RU BR IN CN ZA]
http_basic_authenticate_with name: "***", password: "***", except: [:index, :show]
def index
if params[:search] == nil
@articles = Article.filter(params.slice(:category, :country, :src_url, :date, :lang, :keywords, :title, :rel)).where(is_active: true).order('id DESC').paginate(:page => params[:page])
else
@articles = Article.search(params[:search], :without => {:is_active => false}, :page => params[:page], :per_page => 9, :order => :id)
end
@countries = ISO3166::Country.countries.sort_by do |country|
priority_index = PRIORITY_COUNTRIES.index(country.alpha2)
priority_index.present? ? priority_index.to_s : country.name
end
end
def show
@article = Article.find(params[:id])
end
def new
@article = Article.new
end
def edit
@article = Article.find(params[:id])
end
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render 'edit'
end
end
def destroy
@article = Article.find(params[:id])
@article.update(:is_active => false)
redirect_to articles_path
end
def undelete
@articles = Article.where(is_active: false).paginate(:per_page => 15, :page => params[:page])
end
def undestroy
@article = Article.find(params[:id])
@article.update(:is_active => true)
redirect_to undelete_articles_path
end
private
def article_params
params.require(:article).permit(:title, :date, :src_url, :country, :author, :category, :keywords, :keywords2, :text, :lang, :rel)
end
end
模特:
class Article < ApplicationRecord
before_validation do |article|
article.keywords.reject!(&:blank?) if article.keywords
end
self.per_page = 9
include Filterable
validates :country, presence: true, length: { minimum: 2 }
validates :category, presence: true
validates :src_url, presence: true
validates :keywords2, presence: true
validates :text, presence: true, length: { minimum: 5 }
validates :date, presence: true
scope :country, -> (country) { where country: country }
scope :category, -> (category) { where category: category }
scope :src_url, -> (src_url) { where('src_url like ?', "%#{src_url}%")}
scope :date, -> (date) { where date: date }
scope :keywords, -> (keywords) { where('keywords like ?', "%#{keywords}%")}
scope :title, -> (title) { where('title LIKE ?', "%#{title}%")}
scope :rel, -> (rel) { where rel: rel }
end
答案 0 :(得分:0)
您正走在正确的轨道上,加入了关键字。但是,您可能会更好地处理模型层的字符串要求。
由于列需要字符串,但表单和控制器传递数组,您可以考虑执行以下操作:
class Article < ApplicationRecord
...
def keywords=(value)
return super value.join(", ") if value.is_a?(Array)
super
end
end
这将覆盖模型中的keywords
setter,在传递数组的情况下传递连接的字符串。
答案 1 :(得分:0)
我相信在传递给控制器时,对字符串字段使用多重选择将被格式化为JSON数组。
因此,击中控制器的参数类似于以下内容:
{ keywords: { keywords: '["kw1", "kw12"]' } }
因此,要将它作为逗号分隔的字符串存储在数据库中,您需要先使用以下内容解析它:
JSON.parse(params[:keywords][:keywords]).reject(&:blank?).join(', ')
这里有几个问题:
使用像这样的多选通常(总是?)首先返回一个空值,因此reject(&:blank?)
。
如果params返回nil
,尝试解析这会引发错误,因此您可能希望定义一个方法来处理此问题,例如:
def string_from_json(vals)
return unless vals.present?
JSON.parse(vals).reject(&:blank?).join(', ')
end
或者你可以救出JSON::ParseError
或其他东西。
最后,你打电话给keywords = string_from_json(params[:keywords][:keywords])
来获取字符串。
希望有所帮助!
编辑:
那将处理解析,然后您可以在控制器中使用控制器中的简单@article.keywords = keywords
,@article.update_attribute(:keywords, keywords)
或Daniel推荐的方法进行解析。