webmagnets
webmagnets

Reputation: 2296

How can I make a delayed job for this custom method?

Here is my Lesson model:

#encoding: utf-8

class Lesson < ActiveRecord::Base
    attr_accessible :content, :title, :parsed_content, :html_content, :user_id

    serialize :parsed_content, Array
    serialize :html_content, Array
    serialize :pinyin_content, Array
    serialize :defined_content, Array
    serialize :literal_content, Array

    validates :title, :presence => true
    validates :content, :presence => true

    belongs_to :user

    before_update do |lesson|
        lesson.makesandwich
    end

    before_save do |lesson|
        lesson.delay.makesandwich
    end

    def makesandwich

        require 'rmmseg'
                                                          #require 'to_lang'
        require 'bing_translator'
        require 'ruby-pinyin'

        self.parsed_content = []

        RMMSeg::Dictionary.load_dictionaries

        content               = self.content
        paragraphs            = content.split(/\r\n\r\n/) #convert to array of paragraphs
        self.parsed_content = paragraphs
        paragraphs.each_with_index do |text, ti|

            text = text.gsub("。", "^^.")
            text = text.gsub("?", "~~?")
            text = text.gsub("!", "||!")
            text = text.gsub(":", ":")  #fix missing colons

            text = text.split(/[.?!]/u) #convert to an array
            text.each do |s|
                s.gsub!("^^", "。")
                s.gsub!("~~", "?")
                s.gsub!("||", "!")
                #s.gsub!("———————————",":")
            end

            text.each_with_index do |val, index|
                algor     = RMMSeg::Algorithm.new(text[index])
                splittext = []
                loop do
                    tok = algor.next_token
                    break if tok.nil?
                    tex = tok.text.force_encoding('UTF-8')
                    splittext << tex
                    text[index] = splittext
                end
                paragraphs[ti] = text
            end
        end
        bing                   = BingTranslator.new(BING_API)
        self.parsed_content  = paragraphs
        textarray              = Marshal.load(Marshal.dump(paragraphs))
        self.defined_content = Marshal.load(Marshal.dump(paragraphs))
        self.literal_content = Marshal.load(Marshal.dump(paragraphs))
        self.pinyin_content  = Marshal.load(Marshal.dump(paragraphs))
        textarray.each_with_index do |paragraph, pi|
            paragraph.each_with_index do |sentence, si|
                sentence.each_with_index do |word, wi|
                    if DictionaryEntry.find_by_simplified(word) != nil
                        self.defined_content[pi][si][wi] = DictionaryEntry.find_by_simplified(word).definition
                        #self.literal_content is down below
                        self.pinyin_content[pi][si][wi]  = DictionaryEntry.find_by_simplified(word).pinyin
                    else
                        self.defined_content[pi][si][wi] = bing.translate(word, :from => 'zh-CHS', :to => 'en')
                        #self.defined_content[pi][si][wi] = word
                        #self.literal_content is down below
                        if PinYin.of_string(word, true).length > 1 #for punctuation
                            self.pinyin_content[pi][si][wi] = PinYin.of_string(word, true).join(" ").downcase
                        else
                            self.pinyin_content[pi][si][wi] = word
                        end
                    end
                end
            end
        end

        #Literal
        literalarray = Marshal.load(Marshal.dump(paragraphs))
        literalarray.each_with_index do |paragraph, pi|
            paragraph.each_with_index do |sentence, si| #iterate array of sentence
                literalarray[pi][si] = []
                sentence.each_with_index do |word, wi| #iterate sentence's array of words
                    entrytobesliced = DictionaryEntry.find_by_simplified(word)
                    slicedentry     = []

                    if entrytobesliced == nil
                        if word.length > 1 && word !~ /\w/ #/^\s*\w\d+\s*$/ #number regex  #for cases where there is no DictionaryEntry
                            split     = []
                            wordarray = word.split("").each_with_index() do |ws, wsi|
                                split << [DictionaryEntry.find_by_simplified(ws).definition]
                            end
                            literalarray[pi][si] << split
                        else
                            literalarray[pi][si] << [word] #in case none of the above work
                        end
                    else
                        entrytobesliced.simplified.each_char do |w|
                            singlechar = DictionaryEntry.find_by_simplified(w)
                            slicedentry << singlechar.definition.split("\", \"")
                        end
                        literalarray[pi][si] << slicedentry
                    end
                    self.literal_content = literalarray #slicedentry #literalarray
                end
            end


        end
    end
end

When I try to create a new lesson it errors like this: Jobs cannot be created for records before they've been persisted

But if I change it to after_save instead of before_save then I can see the work run, but it doesn't update the serialized arrays in the database.

Can someone please help me implement delayed_jobs for this? It was working when I had:

    before_save do |lesson|
        lesson.makesandwich #no delay
    end

Upvotes: 1

Views: 1643

Answers (1)

mu is too short
mu is too short

Reputation: 434695

I think you're getting these errors:

Jobs cannot be created for records before they've been persisted

because your Lesson instances won't have an id until they've been saved and without an id, DJ has no way to know which instance it should be working with. So you have to use an after_save so that your Lesson has an id and can be uniquely identified. But then your updates from the delayed job won't be saved because, well, nothing asks for them to be saved. You should be able to get around that simply by adding a self.save or self.save! call at the end of makesandwich.

Upvotes: 2

Related Questions