Class: Sitemap::Generator

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/sitemap/generator.rb

Constant Summary collapse

SEARCH_ATTRIBUTES =
{
  :updated_at       => "lastmod",
  :change_frequency => "changefreq",
  :priority         => "priority"
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeGenerator

Instantiates a new object. Should never be called directly.



17
18
19
20
21
22
23
24
# File 'lib/sitemap/generator.rb', line 17

def initialize
  self.class.send(:include, Rails.application.routes.url_helpers)
  self.fragments = []
  self.store = Store.new(:max_entries => Sitemap.defaults[:max_urls])
  self.store.before_reset do |entries|
    self.process_fragment!
  end
end

Instance Attribute Details

#fragmentsObject

Returns the value of attribute fragments.



13
14
15
# File 'lib/sitemap/generator.rb', line 13

def fragments
  @fragments
end

#hostObject

Returns the value of attribute host.



13
14
15
# File 'lib/sitemap/generator.rb', line 13

def host
  @host
end

#routesObject

Returns the value of attribute routes.



13
14
15
# File 'lib/sitemap/generator.rb', line 13

def routes
  @routes
end

#storeObject

Returns the value of attribute store.



13
14
15
# File 'lib/sitemap/generator.rb', line 13

def store
  @store
end

Instance Method Details

#build!Object

Generates fragments.



138
139
140
141
# File 'lib/sitemap/generator.rb', line 138

def build!
  instance_exec(self, &routes)
  process_fragment! unless store.entries.empty?
end

#file_url(path = "sitemap.xml") ⇒ Object

URL to the sitemap file.

Defaults to sitemap.xml.



164
165
166
# File 'lib/sitemap/generator.rb', line 164

def file_url(path = "sitemap.xml")
  URI::HTTP.build(:host => host, :path => File.join("/", path)).to_s
end

#load(options = {}, &block) ⇒ Object

Sets the urls to be indexed.

The host, or any other global option can be set here:

Sitemap::Generator.instance.load :host => "mywebsite.com" do
  ...
end

Simple paths can be added as follows:

Sitemap::Generator.instance.load :host => "mywebsite.com" do
  path :faq
end

Object collections are supported too:

Sitemap::Generator.instance.load :host => "mywebsite.com" do
  resources :activities
end

Search options such as frequency and priority can be declared as an options hash:

Sitemap::Generator.instance.load :host => "mywebsite.com" do
  path :root, :priority => 1
  path :faq, :priority => 0.8, :change_frequency => "daily"
  resources :activities, :change_frequency => "weekly"
end


54
55
56
57
58
59
# File 'lib/sitemap/generator.rb', line 54

def load(options = {}, &block)
  options.each do |k, v|
    self.send("#{k}=", v)
  end
  self.routes = block
end

#path(object, options = {}) ⇒ Object

Adds the specified url or object (such as an ActiveRecord model instance). In either case the data is being looked up in the current application routes.

Params can be specified as follows:

# config/routes.rb
match "/frequent-questions" => "static#faq", :as => "faq"

# config/sitemap.rb
path :faq, :params => { :filter => "recent" }

The resolved url would be http://mywebsite.com/frequent-questions?filter=recent.



74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/sitemap/generator.rb', line 74

def path(object, options = {})
  params = Sitemap.defaults[:params].clone.merge!(options[:params] || {})
  params[:host] ||= host # Use global host if none was specified.
  params.merge!(params) { |type, value| get_data(object, value) }

  search = Sitemap.defaults[:search].clone.merge!(options.select { |k, v| SEARCH_ATTRIBUTES.keys.include?(k) })
  search.merge!(search) { |type, value| get_data(object, value) }

  self.store << {
    :object => object,
    :search => search,
    :params => params
  }
end

#process_fragment!Object

Creates a temporary file from the existing entries.



130
131
132
133
134
135
# File 'lib/sitemap/generator.rb', line 130

def process_fragment!
  file = Tempfile.new("sitemap.xml")
  file.write(render)
  file.close
  self.fragments << file
end

#remove_saved_files(location) ⇒ Object



168
169
170
171
172
# File 'lib/sitemap/generator.rb', line 168

def remove_saved_files(location)
  root = File.join(Pathname.new(location).dirname, "sitemaps")
  Dir[File.join(root, "sitemap-fragment-*.xml")].each { |file| File.unlink(file) }
  File.unlink(location) if File.exist?(location)
end

#render(object = "fragment") ⇒ Object

Parses the loaded data and returns the xml entries.



123
124
125
126
127
# File 'lib/sitemap/generator.rb', line 123

def render(object = "fragment")
  xml = Builder::XmlMarkup.new(:indent => 2)
  file = File.read(File.expand_path("../../views/#{object}.xml.builder", __FILE__))
  instance_eval file
end

#resources(type, options = {}) ⇒ Object

Adds the associated object types.

The following will map all Activity entries, as well as the index (/activities) page:

resources :activities

You can also specify which entries are being mapped:

resources :articles, :objects => proc { Article.published }

To skip the index action and map only the records:

resources :articles, :skip_index => true

As with the path, you can specify params through the params options hash. The params can also be build conditionally by using a proc:

resources :activities, :params => { :host => proc { |activity| [activity.location, host].join(".") } }, :skip_index => true

In this case the host will change based the each of the objects associated location attribute. Because the index page doesn’t have this attribute it’s best to skip it.



111
112
113
114
115
116
117
118
119
120
# File 'lib/sitemap/generator.rb', line 111

def resources(type, options = {})
  path(type) unless options[:skip_index]
  link_params = options.reject { |k, v| k == :objects }
  get_objects = lambda {
    options[:objects] ? options[:objects].call : type.to_s.classify.constantize
  }
  get_objects.call.find_each(:batch_size => Sitemap.defaults[:query_batch_size]) do |object|
    path(object, link_params)
  end
end

#save(location) ⇒ Object

Creates the sitemap index file and saves any existing fragments.



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/sitemap/generator.rb', line 144

def save(location)
  if fragments.length == 1
    FileUtils.mv(fragments.first.path, location)
  else
    remove_saved_files(location)
    root = File.join(Pathname.new(location).dirname, "sitemaps")
    Dir.mkdir(root) unless File.directory?(root)
    fragments.each_with_index do |fragment, i|
      file_pattern = File.join(root, "sitemap-fragment-#{i + 1}.xml")
      FileUtils.mv(fragment.path, file_pattern)
    end
    file = File.new(location, "w")
    file.write(render "index")
    file.close
  end
end