【发布时间】:2019-05-19 06:03:12
【问题描述】:
我正在尝试创建一个表单,以便用户可以保存一个setting,该表单具有默认的teams(多个)和professions(单个)。我可以使用simple_form 和下面的代码行来做到这一点,但我正在尝试使用自动完成,因为下拉列表不适用于我的设计。
<%= f.association :profession %><%= f.association :team, input_html: { multiple: true } %>
我正在将集合中的 JSON 加载到我的 inputs 中的属性 data-autocomplete-source 中,一小段 jquery 然后循环遍历这些属性,然后初始化物化 .autocomplete,我还需要这样做这与 .chips 对于许多协会。
UI 元素可以正常工作,但我不知道如何保存新记录。我有两个问题:
-
Unpermitted parameters: :team_name, :profession_name- 我一直在尝试调整 tutorial 并相信第 11 步会在模型中有效地转换它,但我显然不明白什么... -
"setting"=>{"team_name"=>"", "profession_name"=>"Consultant Doctor"}- 尝试保存记录时无法识别team_name值(即chips)。我有一些讨厌的 jquery 将id从div转移到生成的input我希望它可以工作......
我也查了很多之前关于 Stack Overflow 的问题(其中一些似乎和这个问题类似,一般使用 jqueryui),但不知道如何调整答案。
如何在具体化 chip 和 autocomplete 输入中使用模型中的名称,并将其关联的 id 的选择保存到记录中?
任何帮助或指导将不胜感激。
setting.rb
class Setting < ApplicationRecord
has_and_belongs_to_many :team, optional: true
belongs_to :user
belongs_to :profession
def team_name
team.try(:name)
end
def team_name=(name)
self.team = Team.find_by(name: name) if name.present?
end
def profession_name
profession.try(:name)
end
def profession_name=(name)
self.profession = Profession.find_by(name: name) if name.present?
end
end
settings_controller.rb
def new
@user = current_user
@professions = Profession.all
@teams = Team.all
@setting = Setting.new
@teams_json = @teams.map(&:name)
@professions_json = @professions.map(&:name)
render layout: "modal"
end
def create
@user = current_user
@setting = @user.settings.create(setting_params)
if @setting.save
redirect_to action: "index"
else
flash[:success] = "Failed to save settings"
render "new"
end
end
private
def setting_params
params.require(:setting).permit(:user_id, :contact, :view, :taketime, :sortname, :sortlocation, :sortteam, :sortnameorder, :sortlocationorder, :sortteamorder, :location_id, :profession_id, :department_id, team_ids: [])
end
views/settings/new.html.erb
<%= simple_form_for @setting do |f| %>
<div class="row">
<div class="col s12">
<div class="row">
<div class="input-field autocomplete_dynamic col s12">
<i class="material-icons prefix">group</i>
<div data-autocomplete-source='<%= @teams_json %>' class="string optional chips" type="text" name="setting[team_name]" id="setting_team_name"></div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col s12">
<div class="row">
<div class="input-field autocomplete_dynamic col s12">
<i class="material-icons prefix">group</i>
<%= f.input :profession_name, wrapper: false, label: false, as: :search, input_html: {:data => {autocomplete_source: @professions_json} } %>
<label for="autocomplete-input">Select your role</label>
</div>
</div>
</div>
</div>
<%= f.submit %>
<% end %>
$("*[data-autocomplete-source]").each(function() {
var items = [];
var dataJSON = JSON.parse($(this).attr("data-autocomplete-source"));
var i;
for (i = 0; i < dataJSON.length; ++i) {
items[dataJSON[i]] = null;
}
if ($(this).hasClass("chips")) {
$(this).chips({
placeholder: $(this).attr("placeholder"),
autocompleteOptions: {
data: items,
limit: Infinity,
minLength: 1
}
});
// Ugly jquery to give the generated input the correct id and name
idStore = $(this).attr("id");
$(this).attr("id", idStore + "_wrapper");
nameStore = $(this).attr("name");
$(this).attr("name", nameStore + "_wrapper");
$(this).find("input").each(function() {
$(this).attr("id", idStore);
$(this).attr("name", nameStore);
});
} else {
$(this).autocomplete({
data: items,
});
}
});
.prefix~.chips {
margin-top: 0px;
}
<!-- jquery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Materialize CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!-- Materialize JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<!-- Material Icon Webfont -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<div class="row">
<div class="col s12">
<div class="row">
<div class="input-field autocomplete_dynamic col s12">
<i class="material-icons prefix">group</i>
<div data-autocomplete-source='["Miss T","Mr C","Mr D","Medicine Take","Surgery Take"]' class="string optional chips" type="text" name="setting[team_name]" id="setting_team_name"></div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col s12">
<div class="row">
<div class="input-field autocomplete_dynamic col s12">
<i class="material-icons prefix">group</i>
<input class="string optional input-field" data-autocomplete-source='["Consultant Doctor","Ward Clerk","Nurse","Foundation Doctor (FY1)","Foundation Doctor (FY2)","Core Trainee Doctor (CT2)","Core Trainee Doctor (CT1)"]' type="text" name="setting[profession_name]"
id="setting_profession_name">
<label for="autocomplete-input">Select your role</label>
</div>
</div>
</div>
</div>
宝石和版本
- 红宝石'2.5.0'
- gem 'rails', '~> 5.2.1'
- gem 'materialize-sass'
- gem 'material_icons'
- 宝石 '实体化形式'
- gem 'simple_form', '>= 4.0.1'
- 宝石 'client_side_validations'
- gem 'client_side_validations-simple_form'
【问题讨论】:
-
控制器中的
setting_params方法是什么样的? -
将其添加到问题中-我已在此处添加
profession_name..认为这会带来安全风险?感谢您的帮助 -
你的HABTM关系需要复数
teams。我还强烈建议您删除 HABTM 并使用has_many :through,以便您可以为defaut_team添加一个字段。问题 1 可以通过在permit参数哈希中添加:team_name和:profession_name到settings_controller#setting_params来解决。对于问题 2,我会阅读 Rails Nested Forms 和 Materialize Chips。两者都存在多个问题。老实说,所需更改的范围超出了一个问题。 -
感谢汤姆的指点。我永远不会希望用户从这个表单中创建一个团队,只创建与现有的关联。嵌套方法仍然是最好的吗?如果是的话,很高兴能更详细地研究它。再次感谢
-
如果您不修改或创建标签,那么您将不需要执行嵌套表单。很抱歉对于这个误会。
team_ids: []是正确的。您将需要您的自动完成输入来返回name="setting[team_ids][]"下的筹码。 Rails 需要空括号将其解析为数组。出于好奇,您为什么不使用表单助手?
标签: javascript jquery ruby-on-rails ruby materialize