- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我正在尝试创建一个表单,以便用户可以保存 setting
有默认的 teams
(多个)及其 professions
(单例的)。我可以使用 simple_form
来做到这一点和下面的代码行,但我正在尝试使用自动完成功能,因为下拉列表不适合我的设计。
<%= f.association :profession %>
<%= f.association :team, input_html: { multiple: true } %>
我正在将集合中的 JSON 加载到属性中 data-autocomplete-source
在我的inputs
, 一小段 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
输入并保存选择进入记录?
如有任何帮助或指导,我们将不胜感激。
设置.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>
gem 和版本
最佳答案
This is almost certainly not the best way of doing this, but it does work. Please offer suggestions and I will update this, or if someone adds a better answer I will happily mark it as correct. This solution doesn't require much in the way of controller/model changes and is largely done with a (comparatively) short bit of jquery/JS so can be easily repeated within a project.
我已经设法让自动完成和芯片与 Ruby on Rails 一起工作,尽可能使用 simple_form 表单助手。
实际上,我将 JSON 存储到每个案例的自定义属性中,然后在加载 View 时使用一些 jquery/javascript 对其进行解析,然后再使用它来初始化 autocomplete
或 chips
.
自动完成值在 Controller 中从名称转换为 ID。
Chip 值被一些 JS 识别为客户端,并使用正确的 name
创建输入和 id
对于 simpleform 自动将值作为数组保存到散列中。
完整的解释和代码如下。
感谢Tom感谢他的有益评论和意见。
autocomplete
要求您在variable_name 下创建一个输入,然后在模型中添加额外的函数以将名称转换为id 进行保存。有效地遵循此 tutorial .
<%= f.input :profession_name, input_html: { data: { autocomplete: @professions_json } } %>
正如您在上面看到的,与添加典型的 simple_form 关联的唯一真正区别如下:
f.input
而不是 f.association
- 确保呈现文本框而不是下拉列表:model_name
而不是 :model
- 确保 Controller 识别出这是一个需要转换为对象的名称input_html: { data: { autocomplete: @model_json } }
- 这会添加一个包含所有 JSON 数据的自定义属性,这是由 您需要确保模型的名称是唯一的。
chips
这有点复杂,需要额外的 javascript 函数。代码在添加或移除筹码的事件中附加回调,然后循环遍历每个筹码并添加隐藏的 input
。 .每个输入都有一个与 simple_form 期望匹配的名称属性,因此在提交给 Controller 之前将其正确添加到哈希参数中。我无法让它翻译数组中的多个名称,所以只是让它重新读取原始 JSON 中的 id 并将其添加为输入值。
<div id="team_ids" placeholder="Add a team" name="setting[team_ids]" class="chips" data-autocomplete="<%= @teams_json %>"></div>
从上面您可以看到与 simple_form 约定有以下偏差:
<div>
而不是 <% f.input %>
因为需要在 div 上调用 Materialise 芯片placeholder="..."
芯片初始化后,此文本用作占位符,可以留空/不包含name="setting[team_ids]"
帮助 simple_form 了解这适用于哪个模型class="chips"
确保我们的 javascript 稍后知道初始化 chips
在这个元素上data-autocomplete="<%= @teams_json %>"
将JSON数据保存为div的一个属性,以供后续解析Currently the code re-parses the original JSON attribute, it is possible to reference the JSON data that is created on initialisation of the chips, this is likely better but I could not get it to work.
Custom Input Element - someone more experience than myself might be able to play around with this and create a custom element for simple_form... it was beyond me unfortunately.
settings_controller.rb
class SettingsController < ApplicationController
...
def new
@user = current_user
@setting = Setting.new
@professions = Profession.select(:name)
@teams = Team.select(:id, :name)
# Prepare JSON for autocomplete and chips
@teams_json = @teams.to_json(:only => [:id, :name] )
@professions_json = @professions.to_json(:only => [:name] )
end
....
private
def setting_params
params.require(:setting).permit( :profession_name, :user_id, :profession_id, team_ids: [])
end
设置.rb
class Setting < ApplicationRecord
has_and_belongs_to_many :teams, optional: true
belongs_to :user
belongs_to :profession, optional: true
def profession_name
profession.try(:name)
end
def profession_name=(name)
self.profession = Profession.find_by(name: name) if name.present?
end
_form.html.erb 注意这是部分的,如前面的下划线所示
<%= simple_form_for @setting, validate: true, remote: true do |f| %>
<%= f.input :profession_name, input_html: { data: { autocomplete: @professions_json } } %>
<div id="team_ids" placeholder="Add a team" name="setting[team_ids]" class="chips" data-autocomplete="<%= @teams_json %>"></div>
<%= f.submit %>
<% end %>
$(document).ready(function() {
// Cycle through anything with an data-autocomplete attribute
// Cannot use 'input' as chips must be innitialised on a div
$("[data-autocomplete]").each(function() {
var dataJSON = JSON.parse($(this).attr("data-autocomplete"));
// Prepare array for items and add each
var items = [];
var i;
for (i = 0; i < dataJSON.length; ++i) {
items[dataJSON[i].name] = null; // Could assign id to image url and grab this later? dataJSON[i].id
}
// Check if component needs to be a chips
if ($(this).hasClass("chips")) {
// Initialise chips
// Documentation: https://materializecss.com/chips.html
$(this).chips({
placeholder: $(this).attr("placeholder"),
autocompleteOptions: {
data: items,
limit: Infinity,
minLength: 1
},
onChipAdd: () => {
chipChange($(this).attr("id")); // See below
},
onChipDelete: () => {
chipChange($(this).attr("id")); // See below
}
});
// Tweak the input names, etc
// This means we can style the code within the view as we would a simple_form input
$(this).attr("id", $(this).attr("id") + "_wrapper");
$(this).attr("name", $(this).attr("name") + "_wrapper");
} else {
// Autocomplete is much simpler! Just initialise with data
// Documentation: https://materializecss.com/autocomplete.html
$(this).autocomplete({
data: items,
});
}
});
});
function chipChange(elementID) {
// Get chip element from ID
var elem = $("#" + elementID);
// In theory you can get the data of the chips instance, rather than re-parsing it
var dataJSON = JSON.parse(elem.attr("data-autocomplete"));
// Remove any previous inputs (we are about to re-add them all)
elem.children("input[auto-chip-entry=true]").remove();
// Find the wrapping element
wrapElement = elem.closest("div[data-autocomplete].chips")
// Get the input name we need, [] tells Rails that this is an array
formInputName = wrapElement.attr("name").replace("_wrapper", "") + "[]";
// Start counting entries so we can add value to input
var i = 0;
// Cycle through each chip
elem.children(".chip").each(function() {
// Get text of chip (effectively just excluding material icons 'close' text)
chipText = $(this).ignore("*").text();
// Get id from original JSON array
// You should be able to check the initialised Materialize data array.... Not sure how to make that work
var chipID = findElement(dataJSON, "name", chipText);
// ?Check for undefined here, will be rejected by Rails anyway...?
// Add input with value of the selected model ID
$(this).parent().append('<input value="' + chipID + '" multiple="multiple" type="hidden" name="' + formInputName + '" auto-chip-entry="true">');
});
}
// Get object from array of objects using property name and value
function findElement(arr, propName, propValue) {
for (var i = 0; i < arr.length; i++)
if (arr[i][propName] == propValue)
return arr[i].id; // Return id only
// will return undefined if not found; you could return a default instead
}
// Remove text from children, etc
$.fn.ignore = function(sel) {
return this.clone().find(sel || ">*").remove().end();
};
// Print to console instead of posting
$(document).on("click", "input[type=submit]", function(event) {
// Prevent submission of form
event.preventDefault();
// Gather input values
var info = [];
$(this).closest("form").find("input").each(function() {
info.push($(this).attr("name") + ":" + $(this).val());
});
// Prepare hash in easy to read format
var outText = "<h6>Output</h6><p>" + info.join("</br>") + "</p>";
// Add to output if exists, or create if it does not
if ($("#output").length > 0) {
$("#output").html(outText);
} else {
$("form").append("<div id='output'>" + outText + "</div>");
}
});
<!-- 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">
<form class="simple_form new_setting" id="new_setting" novalidate="novalidate" data-client-side-validations="" action="/settings" accept-charset="UTF-8" data-remote="true" method="post"><input name="utf8" type="hidden" value="✓">
<div class="input-field col string optional setting_profession_name">
<input data-autocomplete='[{"id":1,"name":"Consultant Doctor"},{"id":2,"name":"Junior Doctor (FY1)"}]' class="string optional" type="text" name="setting[profession_name]" id="setting_profession_name"
data-target="autocomplete-options-30fe36f7-f61c-b2f3-e0ef-c513137b42f8" data-validate="true">
<label class="string optional" for="setting_profession_name">Profession name</label></div>
<div id="team_ids" name="setting[team_ids]" class="chips input-field" placeholder="Add a team" data-autocomplete='[{"id":1,"name":"Miss T"},{"id":2,"name":"Surgical Take"}]'></div>
<input type="submit" name="commit" value="Create Setting" data-disable-with="Create Setting">
</form>
关于javascript - 在关联模型的 Ruby on Rails 表单中使用 Materialise `chip` 和 `autocomplete`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53839487/
sanitize 是什么意思在 Rails 中是什么意思? 我正在阅读 CanCanCan 的文档.它说: When using strong_parameters or Rails 4+, you
在过去的几个月里,我感觉自己对 Ruby on Rails (RoR) 开发的了解达到了极限。我为大/小客户和 friend /爱好项目开发了大大小小的应用程序。我知道如何开发这些应用程序,但开始感觉
我昨天参加了一个关于扩展 Rails 的聚会,其中一个主题是 Hexagonal Rails。然而,我只做了一年的 Rails,对 MVC 结构非常满意(也许太舒服了),所以我不太了解适配器和消息队列
我使用多个 Rails 应用程序,一些在 Rails 3.2/Ruby 2.0 上,一些在 Rails 2.3/Ruby 1.8.7 上。 他们的共同点是,随着他们的成长和添加更多的依赖项/ gem
这个问题在这里已经有了答案: Using Rails-UJS in JS modules (Rails 6 with webpacker) (5 个答案) 关闭 3 年前。 我正在尝试使用 UJS
我正在开发一个当前使用 Rails 1.2 的 Rails 应用程序,所以我现在离最新的稳定版本(Rails 2.3)还有很长的路要走。 我应该如何进行迁移到更新版本的 Rails 的过程? 我应该一
尝试按照 Ryan Bates Backbone.js 教程构建抽奖应用程序,但我已经遇到了第一段代码的问题。在 application.js 的 init 函数中,他初始化了 Raffler 路由的
我正在使用 Rails 3.2 并且我有一个数据库表,我想在其中找到符合以下条件的所有行: a = true and b = true and ( 0 true, :b =>
我有一个用户类和一个联系人,其中联系人是用户的子类。这两个类都存储在用户表中。 我的联系人可能有也可能没有电子邮件地址,而我的用户需要一个电子邮件地址(我的用户模型定义中有 validates_pre
我正在编写一个教程,我在其中演示了一些 rails 命令。在我的机器上 rails和 script/rails两者都同样有效。有“首选”形式吗?两者中哪一个更普遍? 最佳答案 当您运行 rails 时
我正在寻找有关通过我的应用程序前进的最佳方式的建议,这是我首次开始集成Elasticsearch。我是一名初学者,但是热衷于深入研究,以便原谅任何明显的错误! 我遵循了http://www.sitep
我刚刚用 Rails new 启动了一个新的 Rails 应用程序,将默认数据库设置更改为 PostgresSQL。我用 bin/rails s 启动服务器,结果很奇怪 2016-04-21 05:0
我收到一个参数并希望它是这样的字符串: "abc,efg" 或者像这样的数组 ["abc","efg"] 在第一种情况下,我想将它转换成一个数组,什么是好的方法? 这是我的想法 if params[:
我刚刚用 Rails new 启动了一个新的 Rails 应用程序,将默认数据库设置更改为 PostgresSQL。我用 bin/rails s 启动服务器,结果很奇怪 2016-04-21 05:0
我收到一个参数并希望它是这样的字符串: "abc,efg" 或者像这样的数组 ["abc","efg"] 在第一种情况下,我想将它转换成一个数组,什么是好的方法? 这是我的想法 if params[:
我有 Rails 4,这是我的默认版本(我仍然希望它是)。但我不想在我的电脑上添加 rails 3.2。在以下命令中:gem install rails -v 3.2.16 我有这个警告: railt
您好,我想使用 Sheevaplug 构建一个“Rails Brick”来自 Marvell(操作系统是开箱即用的 Ubuntu,但您可以在其上安装其他发行版)。它将成为家庭服务器和静音、低成本(99
我需要能够从 Rails 控制台发送我的 Rails 应用程序的 Postgres 数据库中所有未接受的邀请。 (我有一个名为 Invitations 的表,其中包含一个名为 accepted 的 b
validate :cannot_modify_if_locked, on: :update def cannot_modify_if_locked if self.locked erro
我正在学习教程(学习 Rails 播客),需要更改以下路由语法,以便它与 Rails 3.0 兼容。谁能帮忙? map.view_page ':name', :controller => 'viewe
我是一名优秀的程序员,十分优秀!