I have a company model which can have many tags. It works fine, but in one occasion it does not work. The occasion is when company model validation fails. After :render => 'edit' it does not show tags in the view. I suspect the data-pre is not taking the data correctly. I would also like for tags to be preserved when solving validations.
I got this idea from here: http://railscasts.com/episodes/167-more-on-virtual-attributes
I use Input token control: http://loopj.com/jquery-tokeninput/
This is what I have in Company model regarding the tag_tokens:
before_save :save_tag_tokens
attr_writer :tag_tokens
attr_accessible :tag_tokens
def tag_tokens
@tag_tokens || tags.to_json(:only => [:id, :name])
end
def save_tag_tokens
if @tag_tokens
@tag_tokens.gsub!(/CREATE_(.+?)_END/) do
Tag.create!(:name => $1.strip.downcase).id
end
self.tag_ids = @tag_tokens.split(",")
end
end
Here is the code from the view:
<div class="input text no-border">
<% Tag.include_root_in_json = false %>
<%= company_form.label :tag_tokens, t('form.account.company.edit.company_tags_html')%>
<%= company_form.text_field :tag_tokens, :id => 'company_tag_tokens', "data-pre" => @company.tag_tokens%>
<p class="tip"><%= t('form.account.company.edit.tag_tip') %></p>
</div>
EDIT:
OK, so I see what is the problem with the above code.
When i load edit page data-pre contains this: data-pre="[{"id":1704,"name":"dump truck"}]"
. when I submit the form with validation error the data-pre contains: data-pre="1704"
.
if i change the code to this:
def tag_tokens
tags.to_json(:only => [:id, :name])
end
new tags that were not yet save to the company model are removed, because they are read from the DB everytime. How can I preserve the entered data between form transitions?
OK, I've written a solution, it might not be the nicest one, but it works to me! It parses the input token value to JSON format (when validation fails), which is used when loading the page. Under page load it just loads tags from DB.
def tag_tokens
if @tag_tokens
#if there is user info, parse it to json format. create an array
array = @tag_tokens.split(",")
tokens_json = []
#loop through each tag and check if it's new or existing
array.each do |tag|
if tag.to_s.match(/^CREATE_/)
#if new generate json part like this:
tag.gsub!(/CREATE_(.+?)_END/) do
tokens_json << "{\"id\":\"CREATE_#{$1.strip.downcase}_END\",\"name\":\"Add: #{$1.strip.downcase}\"}"
end
else
#if tag is already in db, generate json part like this:
tokens_json << "{\"id\":#{tag},\"name\":\"#{Tag.find_by_id(tag).name}\"}"
end
end
#encapsulate the value for token input with [] and add all tags from array
"[#{tokens_json.to_sentence(:last_word_connector => ',', :words_connector => ',', :two_words_connector => ',')}]"
else
#if there is no user input already load from DB
tags.to_json(:only => [:id, :name])
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With