Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby on Rails - JS Input token, an issue when validation fails

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="[{&quot;id&quot;:1704,&quot;name&quot;:&quot;dump truck&quot;}]". 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?

like image 549
MJM Avatar asked Nov 13 '22 16:11

MJM


1 Answers

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
like image 162
MJM Avatar answered Nov 15 '22 04:11

MJM