#ruby-on-rails #postgresql #ruby-on-rails-4 #concatenation
#ruby-на-рельсах #postgresql #ruby-on-rails-4 #конкатенация #ruby-on-rails
Вопрос:
У меня есть несколько флажков в форме, в которых я сохраняю результаты каждого поля в соответствующих временных полях, которые я указал в модели с атрибутом attr_accessor: . Я хочу объединить содержимое этих полей в одно поле с разделителем-запятой и сохранить его в базе данных.
Моя полная форма выглядит примерно так :
<%= form_for @company do |f| %>
<% if @company.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@company.errors.count, "error") %> prohibited
this company from being saved:</h2>
<ul>
<% @company.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<div class="row">
<div class='col-sm-6'>
<div class="form-group">
<p>
<%= f.label :name %><br>
<%= f.text_field :name,class:'form-control' %>
</p>
<p>
<%= f.label :grade %><br>
<%= f.select(:grade, options_for_select([['Dream', 'dream'], ['A ', 'a '], ['A ', 'a '],['A', 'a']])) %>
</p>
<p>
<%= f.label :beCutoff %><br>
<%= f.text_field :beCutoff,class:'form-control' %>
</p>
<%= f.label :branchesAllowed %><br>
<%= f.check_box :coe, {}, "COE", "" %><%= label_tag :COE %><br>
<%= f.check_box :ece, {}, "ECE", ""%><%= label_tag :ECE %><br>
<%= f.check_box :ice, {}, "ICE", ""%><%= label_tag :ICE %><br>
<%= f.check_box :it, {}, "IT", ""%><%= label_tag :IT %><br>
<%= f.check_box :mpae, {}, "MPAE", ""%><%= label_tag :MPAE %><br>
<%= f.check_box :bt, {}, "BT", ""%><%= label_tag :BT %><br>
<%= f.check_box :is, {}, "IS", ""%><%= label_tag :IS %><br>
<%= f.check_box :sp, {}, "SP", ""%><%= label_tag :SP %><br>
<%= f.check_box :pc, {}, "PC", ""%><%= label_tag :PC %><br>
<p>
<%= f.label :backsAllowed %><br>
<%= f.text_field :backsAllowed,class:'form-control' %>
</p>
<p>
<%= f.label :details %><br>
<%= f.text_field :details,class:'form-control' %>
</p>
<p>
<%= f.label :package %><br>
<%= f.text_field :package,class:'form-control' %>
</p>
<p>
<%= f.label :xiiCutoff %><br>
<%= f.text_field :xiiCutoff,class:'form-control' %>
</p>
<p>
<%= f.label :xCutoff %><br>
<%= f.text_field :xCutoff,class:'form-control' %>
</p>
<%= f.label :deadline %><br>
<div class='input-group date' id='datetimepicker1'>
<%= f.text_field :deadline ,class:'form-control',:readonly=>true%>
<span class="input-group-addon" ><span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
<script type="text/javascript">
$(function () {
$('#datetimepicker1').datetimepicker({format: 'YYYY-MM-DD HH:mm:ss '});
});
</script>
</div>
<p>
<%= f.submit %>
</p>
<% end %>
Я указал поля: coe,: ece,:ice и т. Д. В моей модели как attr_accessor:
class Company < ActiveRecord::Base
attr_accessor :coe,:ece,:ice,:it,:mpae,:bt,:is,:pc,:sp
validate :deadline_on_or_before_now
def deadline_on_or_before_now
errors.add(:deadline, "can't be in the past") if
!deadline.blank? and deadline < (Time.zone.now 19800).to_datetime
end
validates :name, presence: true,
length: { minimum: 2 };
validates :grade,:beCutoff,:details,:package, presence: true;
validates_inclusion_of :beCutoff,:xiiCutoff,:xCutoff, :in=> 0..100,:message=>"Out of Range";
end
Мой контроллер выглядит так:
class CompaniesController < ApplicationController
def new
@company = Company.new
end
def edit
@company = Company.find(params[:id])
end
def update
@company = Company.find(params[:id])
if @company.update(company_params)
redirect_to @company
else
render 'edit'
end
end
def create
@company = Company.new(company_params)
if @company.save
redirect_to @company
else
render 'new'
end
end
def index
@companies = Company.all
end
def destroy
@company = Company.find(params[:id])
@company.destroy
redirect_to companies_path
end
def show
@company = Company.find(params[:id])
end
private
def company_params
params.require(:company).permit(:name, :beCutoff,:grade,:xiiCutoff,:xCutoff,:backsAllowed,:details,:package,:deadline,:branchesAllowed,:coe,:ece,:ice,:it,:mpae,:bt,:is,:sp,:pc) if params[:company]
end
end
Я хочу объединить поля:coe,:ece,:ice и т. Д. И сохранить их в поле:branchesAllowed(строковое поле) с разделителем commma и возможностью разбивать это поле всякий раз, когда мне нужно использовать их отдельно.
Я использую postgresql с rails 4.1.
Комментарии:
1. Я не хочу снова возиться с кодом, поэтому, конечно, метод, который позволяет мне выполнять одноразовый метод изменения, поможет. Но я хотел бы знать оба метода.
Ответ №1:
Если бы я хотел сделать это таким образом, я бы выбрал хэш, хранящийся в строковом поле.
before_save :create_string
def create_string
fields = {}
fields[:coe]=coe
fields[:ece]=ece
# etcetera
branchesAllowed = fields.to_s # hash to string and then store the string
end
А затем для извлечения значений (скажем, в контроллере или представлении):
values = eval(@company.branchesAllowed) # reversely, evaluate string to hash
@coe = values[:coe]
@ece = values[:ece]
# etcetera
Комментарии:
1. Я попробовал @vapire способ решения и сработал для меня, и ваше решение похоже на это. Спасибо за вашу помощь.
2. @Pranav, нет проблем 🙂
Ответ №2:
Самый быстрый и грязный способ — просто объединить поля в методе вашей модели и вызвать этот метод в before_save
обратном вызове:
class Company < ActiveRecord::Base
# . . .
before_save :combine_branches # or choose other callback type respectively
def combine_branches
self.branchesAllowed = ""
self.branchesAllowed = "COE" if coe
self.branchesAllowed = "ECE" if eve
self.branchesAllowed = "ICE" if ice
# … and so on …
end
end
Теперь при вызове save
или update
в вашем контроллере запускается обратный вызов и устанавливается branchesAllowed
поле перед записью в базу данных.
Это, однако, на самом деле не является сухим и не легко расширяемым. Если вы хотите добавить еще одну ветку, вам придется отредактировать как минимум 3 разных места.
Сухое (er) решение может быть примерно следующим:
class Company < ActiveRecord::Base
# keep a constant of possible branches tied to the model
POSSIBLE_BRANCHES = [:coe, :ece, :ice, :it, :mpae, :bt, :is, :pc, :sp]
# add the branches as virtual attributes (only assign methods)
attr_writer *POSSIBLE_BRANCHES
# add virtual attributes reader methods
# --> define every branch as method, that looks if the value is currenly
# stored in the branchesAllowed string and return true or false
POSSIBLE_BRANCHES.each do |pb|
define_method(pb) do
self.banchesAllowed.split(',').include?(pb.to_s.upcase)
end
end
# add the callback to combine the branches
before_save :combine_branches
def combine_branches
self.banchesAllowed = POSSIBLE_BRANCHES.select { |pb| !!self.send(pb) }.map(amp;:upcase).join(',')
end
end
Тогда вы также можете использовать их в своем представлении:
<%= f.label :branchesAllowed %><br>
<% Company::POSSIBLE_BRANCHES.each do |pb| %>
<%= f.check_box pb, {}, pb.to_s.upcase, "" %><%= label_tag pb.to_s.upcase %><br>
<% end %>
Итак, если вы хотите добавить еще одну ветку позже, вы просто добавите еще один символ к константе массива, и все готово. Надеюсь, это поможет.
Обновить
Поскольку boolean
значения в флажках '1'
по умолчанию используют и '0'
(как строки), я не совсем уверен, должны ли методы чтения виртуальных атрибутов возвращать это вместо логического значения.
Комментарии:
1. Я использовал оба способа, и они работали. Просто применил некоторые условия if, и все было идеально. Спасибо
2. Было бы очень полезно, если бы вы указали какой-либо способ, которым я получаю параметры, отмеченные или снятые при редактировании сообщения.
Ответ №3:
Я бы подошел к этому немного по-другому. Предполагая, что это все атрибуты a, Company
которые вы хотите иметь возможность устанавливать, вы можете использовать одно целое поле для хранения этих данных, создав массив типов атрибутов и используя индекс каждого атрибута в этом массиве как двоичное значение, которое вы можете использовать для определения, является ли атрибутустановлено или нет.
Посмотрите этот Railscast для полного объяснения, поскольку Райан делает это намного лучше, чем я: http://railscasts.com/episodes/189-embedded-association
Комментарии:
1. Спасибо @Jon, я ценю вашу помощь. Я также пробовал массивы ранее в своем приложении, но где-то обнаружил, что массивы не являются хорошими вещами в rails. Также я хочу быстро исправить это приложение.
2. Нет ничего плохого в использовании массива в Rails. Кроме того, вы должны предпочесть правильное исправление быстрому исправлению.