开发者

How to resolve 'column identifier is not unique'?

I'm building a url shortener from an outdated guide, which has meant a lot of debugging. The first time I ran the shortener, it worked.

Now, upon submitting a link, it returns this error: 'column identifier is not unique'

 private 
      def self.create_link(original)
        url = Url.create(:original => original)
        if Link.first(:identifier => url.id.to_i.to_s(36)).nil? or !DIRTY_WORDS.include? url.id.to_i.to_s(36)
          link = Link.new(:identifier => url.id.to_i.to_s(36))
          link.url = url
          link.save
          return link
        else 
          create_link(original)
        end
      end
    end 

The error refers to this particular line.

link.save

Thanks in advance for any help!

These are the models.

class Url
  include DataMapper::Resource 
  property  :id,        Serial
  property  :original,  String, :length => 255
  belongs_to    :link
end



class Link 
  include DataMapper::Resource 
  property :identifier, String, :key => true
  property :created_at, DateTime
  has 1, :url 
  has n, :visits

  def self.shorten(original, custom=nil)
    url = Url.first(:original => original)
    return url.link if url
    link = nil
    if custom
      raise 'Someone has already taken this custom URL, sorry' unless 
  Link.first(:identifier => custom).nil?
      raise 'This custom URL is not allowed because of profanity' if 
  DIRTY_WORDS.include? custom
      transaction do |txn|
        link = Link.new(:identifier => custom)
        link.url = Url.create(:original => original)
        link.save
      end
    else 
      transaction do |txn|
        link = create_link(original)
      end
    end 
    return link 
  end 

  private 
  def self.create_link(original)
    url = Url.create(:original => original)
    if Link.first(:identifier => url.id.to_i.to_s(36)).nil? or !DIRTY_WORDS.include? url.id.to_i.to_s(36)
      link = Link.new(:identifier => url.id.to_i.to_s(36))
      link.url = url
      link.save
      return link
    else 
      create_link(original)
    end
  end
end 


class Visit
  include DataMapper::Resource

  property  :id,            Serial
  property  :created_at,    DateTime
  property  :ip,            IPAddress
  property  :country,       String
  belongs_to    :link

  after :create, :set_country

  def set_country
    xml = RestClient.get "http://api.hostip.info/ge开发者_JAVA技巧t_xml.php?ip=#{ip}"
    self.country = XmlSimple.xml_in(xml.to_s, { 'ForceArray' => false})['featureMember']['Hostip']['countryAbbrev']
    self.save
  end

  def self.count_days_bar(identifier,num_of_days)
    visits = count_by_date_with(identifier, num_of_days)
    data, labels = [], []
    visits.each {|visit| data << visit[1]; labels << "#{visit[0].day}/#{visit[0].month}" }
    "http://chart.apis.google.com/chart?chs=820x180&cht=bvs&chxt=x&chco=a4b3f4&chm=N,000000,0,-1,11&chxl=0:|#{labels.join('|')}&chds=0,#{data.sort.last+10}&chd=t:#{data.join(',')}"
  end

  def self.count_country_chart(identifier,map)
    countries, count = [], []
    count_by_country_with(identifier).each {|visit| countries << visit.country; count << visit.count}
    chart = {}
    chart[:map] = "http://chart.apis.google.com/chart?chs=440x220&cht=t&chtm=#{map}&chco=FFFFFF,a4b3f4,0000FF&chld=#{countries.join('')}&chd=t:#{count.join(',')}"
    chart[:bar] = "http://chart.apis.google.com/chart?chs=320x240&cht=bhs&chco=a4b3f4&chm=N,000000,0,-1,11&chbh=a&chd=t:#{count.join(',')}&chxt=x,y&chxl=1:|#{countries.reverse.join('|')}"
    return chart
  end 

  def self.count_by_date_with(identifier,num_of_days)
    visits = repository(:default).adapter.query("SELECT date(created_at) as date, count(*) as count FROM visits where link_ = '#{identifier}' and created_at between CURRENT_DATE-#{num_of_days} and CURRENT_DATE+1 group by date(created_at)")
    dates = (Date.today-num_of_days..Date.today)
    results = {}
    dates.each { |date|
      visits.each { |visit| results[date] = visit.count if visit.date == date }
      results[date] = 0 unless results[date]
    }
    results.sort.reverse 
  end 

  def self.count_by_country_with(identifier)
    respository(:default).adapter.query("SELECT country, count(*) as count FROM visits where link_identifier = '#{identifier}' group by country")
  end
end 


Well until someone more knowledgeable chimes in... I don't know Ruby or Ruby on rails but I do know databases and this sounds EXACTLY like a primary key validation error. I would suspect that your link.id field needs to be unique and the second time you run the program it is generating the same id. Odds are good you either need to create a unique ID or relax the contraint on the ID field to allow duplicates (which could cause problems when you go to retrieve things by id).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜