hydra-tutorial 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +93 -0
- data/README.md +15 -0
- data/Rakefile +10 -0
- data/bin/hydra-tutorial +4 -0
- data/hydra-tutorial.gemspec +16 -0
- data/open-repositories-tutorial.thor +668 -0
- data/or_templates/add_tests/records_controller_spec.rb +7 -0
- data/or_templates/adding_our_models/basic_af_model.rb +5 -0
- data/or_templates/adding_our_models/basic_mods_model.rb +13 -0
- data/or_templates/adding_our_models/basic_om_model.rb +28 -0
- data/or_templates/adding_our_models/mods_desc_metadata.rb +135 -0
- data/or_templates/building_a_basic_rails_app/fedora.yml +14 -0
- data/or_templates/building_a_basic_rails_app/solr.yml +10 -0
- data/or_templates/records_controller.rb +83 -0
- data/or_templates/wiring_it_into_rails/_form.html.erb +31 -0
- data/or_templates/wiring_it_into_rails/show.html.erb +7 -0
- data/templates/application/dataset_hydra_mods_om.rb +13 -0
- data/templates/application/dataset_hydra_om.rb +37 -0
- data/templates/application/datasets_controller.rb +82 -0
- data/templates/application/mods_desc_metadata.rb +135 -0
- data/templates/building_a_basic_rails_app/dataset_af_om.rb +34 -0
- data/templates/building_a_basic_rails_app/dataset_simple_om.rb +24 -0
- data/templates/building_a_basic_rails_app/fedora.yml +14 -0
- data/templates/building_a_basic_rails_app/om_record.rb +63 -0
- data/templates/building_a_basic_rails_app/solr.yml +10 -0
- data/tutorial.thor +493 -0
- metadata +127 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
class ModsDescMetadata < ActiveFedora::NokogiriDatastream
|
2
|
+
# MODS XML constants.
|
3
|
+
|
4
|
+
MODS_NS = 'http://www.loc.gov/mods/v3'
|
5
|
+
MODS_SCHEMA = 'http://www.loc.gov/standards/mods/v3/mods-3-3.xsd'
|
6
|
+
MODS_PARAMS = {
|
7
|
+
"version" => "3.3",
|
8
|
+
"xmlns:xlink" => "http://www.w3.org/1999/xlink",
|
9
|
+
"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
|
10
|
+
"xmlns" => MODS_NS,
|
11
|
+
"xsi:schemaLocation" => "#{MODS_NS} #{MODS_SCHEMA}",
|
12
|
+
}
|
13
|
+
|
14
|
+
# OM terminology.
|
15
|
+
|
16
|
+
set_terminology do |t|
|
17
|
+
t.root :path => 'mods', :xmlns => MODS_NS
|
18
|
+
t.originInfo do
|
19
|
+
t.dateOther
|
20
|
+
end
|
21
|
+
t.abstract
|
22
|
+
t.titleInfo do
|
23
|
+
t.title
|
24
|
+
end
|
25
|
+
|
26
|
+
t.title :ref => [:mods, :titleInfo, :title]
|
27
|
+
t.name do
|
28
|
+
t.namePart
|
29
|
+
t.role do
|
30
|
+
t.roleTerm
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
t.relatedItem do
|
35
|
+
t.titleInfo do
|
36
|
+
t.title
|
37
|
+
end
|
38
|
+
t.location do
|
39
|
+
t.url
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
t.subject do
|
44
|
+
t.topic
|
45
|
+
end
|
46
|
+
|
47
|
+
t.preferred_citation :path => 'note', :attributes => { :type => "preferred citation" }
|
48
|
+
t.related_citation :path => 'note', :attributes => { :type => "citation/reference" }
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
# Blocks to pass into Nokogiri::XML::Builder.new()
|
53
|
+
|
54
|
+
define_template :name do |xml|
|
55
|
+
xml.name {
|
56
|
+
xml.namePart
|
57
|
+
xml.role {
|
58
|
+
xml.roleTerm(:authority => "marcrelator", :type => "text")
|
59
|
+
}
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
define_template :relatedItem do |xml|
|
64
|
+
xml.relatedItem {
|
65
|
+
xml.titleInfo {
|
66
|
+
xml.title
|
67
|
+
}
|
68
|
+
xml.location {
|
69
|
+
xml.url
|
70
|
+
}
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
define_template :related_citation do |xml|
|
75
|
+
xml.note(:type => "citation/reference")
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.xml_template
|
79
|
+
Nokogiri::XML::Builder.new do |xml|
|
80
|
+
xml.mods(MODS_PARAMS) {
|
81
|
+
xml.originInfo {
|
82
|
+
xml.dateOther
|
83
|
+
}
|
84
|
+
xml.abstract
|
85
|
+
xml.titleInfo {
|
86
|
+
xml.title
|
87
|
+
}
|
88
|
+
xml.name {
|
89
|
+
xml.namePart
|
90
|
+
xml.role {
|
91
|
+
xml.roleTerm
|
92
|
+
}
|
93
|
+
}
|
94
|
+
xml.relatedItem {
|
95
|
+
xml.titleInfo {
|
96
|
+
xml.title
|
97
|
+
}
|
98
|
+
xml.location {
|
99
|
+
xml.url
|
100
|
+
}
|
101
|
+
}
|
102
|
+
xml.subject {
|
103
|
+
xml.topic
|
104
|
+
}
|
105
|
+
xml.note(:type => "preferred citation")
|
106
|
+
xml.note(:type => "citation/reference")
|
107
|
+
}
|
108
|
+
end.doc
|
109
|
+
end
|
110
|
+
|
111
|
+
def insert_person
|
112
|
+
insert_new_node(:name)
|
113
|
+
end
|
114
|
+
|
115
|
+
def insert_related_item
|
116
|
+
insert_new_node(:relatedItem)
|
117
|
+
end
|
118
|
+
|
119
|
+
def insert_related_citation
|
120
|
+
insert_new_node(:related_citation)
|
121
|
+
end
|
122
|
+
|
123
|
+
def insert_new_node(term)
|
124
|
+
add_child_node(ng_xml.root, term)
|
125
|
+
end
|
126
|
+
|
127
|
+
def remove_node(term, index)
|
128
|
+
node = self.find_by_terms(term.to_sym => index.to_i).first
|
129
|
+
unless node.nil?
|
130
|
+
node.remove
|
131
|
+
self.dirty = true
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Dataset < ActiveFedora::Base
|
2
|
+
|
3
|
+
class DatastreamMetadata < ActiveFedora::NokogiriDatastream
|
4
|
+
|
5
|
+
##
|
6
|
+
# Here's the important part. We're mapping XML into Ruby.
|
7
|
+
set_terminology do |t|
|
8
|
+
t.root :path => 'root', :xmlns => nil
|
9
|
+
t.title
|
10
|
+
t.author
|
11
|
+
t.url
|
12
|
+
t.description
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.xml_template
|
16
|
+
Nokogiri::XML::Builder.new do |xml|
|
17
|
+
xml.root do
|
18
|
+
xml.title
|
19
|
+
xml.author
|
20
|
+
xml.url
|
21
|
+
xml.description
|
22
|
+
end
|
23
|
+
end.doc
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
has_metadata :name => "descMetadata", :type => DatastreamMetadata
|
28
|
+
|
29
|
+
delegate :title, :to=>'descMetadata', :unique=>true
|
30
|
+
delegate :author, :to=>'descMetadata', :unique=>true
|
31
|
+
delegate :url, :to=>'descMetadata', :unique=>true
|
32
|
+
delegate :description, :to=>'descMetadata', :unique=>true
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Dataset < OmRecord # OmRecord contains code that lets us pretend this Dataset is a drop-in replacement for the ActiveRecord.
|
2
|
+
include OM::XML::Document
|
3
|
+
|
4
|
+
##
|
5
|
+
# Here's the important part. We're mapping XML into Ruby.
|
6
|
+
set_terminology do |t|
|
7
|
+
t.root :path => 'root', :xmlns => nil
|
8
|
+
t.title
|
9
|
+
t.author
|
10
|
+
t.url
|
11
|
+
t.description
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.xml_template
|
15
|
+
Nokogiri::XML::Builder.new do |xml|
|
16
|
+
xml.root do
|
17
|
+
xml.title
|
18
|
+
xml.author
|
19
|
+
xml.url
|
20
|
+
xml.description
|
21
|
+
end
|
22
|
+
end.doc
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
development:
|
2
|
+
user: fedoraAdmin
|
3
|
+
password: fedoraAdmin
|
4
|
+
url: http://127.0.0.1:8983/fedora
|
5
|
+
test: &TEST
|
6
|
+
user: fedoraAdmin
|
7
|
+
password: fedoraAdmin
|
8
|
+
url: <%= "http://127.0.0.1:#{ENV['TEST_JETTY_PORT'] || 8983}/fedora-test" %>
|
9
|
+
production:
|
10
|
+
user: fedoraAdmin
|
11
|
+
password: fedoraAdmin
|
12
|
+
url: http://your.production.server:8080/fedora
|
13
|
+
cucumber:
|
14
|
+
<<: *TEST
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class OmRecord
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
##
|
6
|
+
# This stuff is so we can store and retrieve data off the filesystem. Don't worry about it.
|
7
|
+
extend ActiveModel::Naming
|
8
|
+
include ActiveModel::Conversion
|
9
|
+
|
10
|
+
attr_writer :file
|
11
|
+
|
12
|
+
attr_accessor :name
|
13
|
+
attr_reader :errors
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize options={}
|
17
|
+
|
18
|
+
@errors = ActiveModel::Errors.new(self)
|
19
|
+
|
20
|
+
self.ng_xml = self.class.xml_template
|
21
|
+
|
22
|
+
options.each do |k,v|
|
23
|
+
send("#{k}=", v)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def file
|
28
|
+
@file ||= "db/datasets/#{Time.now.to_i}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def id
|
32
|
+
File.basename(file)
|
33
|
+
end
|
34
|
+
|
35
|
+
def save
|
36
|
+
File.open(file, 'w') { |f| f.puts ng_xml.to_s }
|
37
|
+
end
|
38
|
+
|
39
|
+
def persisted?
|
40
|
+
File.exists? file
|
41
|
+
end
|
42
|
+
|
43
|
+
class ClassMethods
|
44
|
+
def all
|
45
|
+
Dir.glob('db/datasets/*').map do |f|
|
46
|
+
Dataset.from_file(f)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def find id
|
51
|
+
Dataset.from_file("db/datasets/#{id}")
|
52
|
+
end
|
53
|
+
|
54
|
+
def from_file f
|
55
|
+
d = Dataset.from_xml(File.read(f))
|
56
|
+
|
57
|
+
d.file = f
|
58
|
+
|
59
|
+
d
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# This is a sample config file that does not have multiple solr instances. You will also need to be sure to
|
2
|
+
# edit the fedora.yml file to match the solr URL for active-fedora.
|
3
|
+
development:
|
4
|
+
url: http://localhost:8983/solr/development
|
5
|
+
test: &TEST
|
6
|
+
url: <%= "http://127.0.0.1:#{ENV['TEST_JETTY_PORT'] || 8983}/solr/test" %>
|
7
|
+
cucumber:
|
8
|
+
<<: *TEST
|
9
|
+
production:
|
10
|
+
url: http://your.production.server:8080/bl_solr/core0
|
data/tutorial.thor
ADDED
@@ -0,0 +1,493 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'thor'
|
5
|
+
require 'thor/group'
|
6
|
+
require 'rails/generators/actions'
|
7
|
+
require 'active_support/core_ext/array/extract_options'
|
8
|
+
|
9
|
+
$base_templates_path = File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
10
|
+
|
11
|
+
class HydraTutorialApp < Thor::Group
|
12
|
+
class_option :quick, :default => false
|
13
|
+
|
14
|
+
def welcome
|
15
|
+
$quick = options[:quick]
|
16
|
+
say %Q{
|
17
|
+
Welcome to this Hydra tutorial. We're going to go through some steps to
|
18
|
+
set up a working Hydra head. We'll build the application gradually, and give you
|
19
|
+
opportunities to stop and look around on the way.
|
20
|
+
}, Thor::Shell::Color::YELLOW
|
21
|
+
|
22
|
+
if $quick
|
23
|
+
say %Q{
|
24
|
+
We'll quickly build the application, give you some Hydra models, and send you on your way.
|
25
|
+
}, Thor::Shell::Color::YELLOW
|
26
|
+
|
27
|
+
else
|
28
|
+
say %Q{
|
29
|
+
We'll go through this tour slowly, starting by creating a pure Rails application,
|
30
|
+
and then introduce Hydra components. If you want to speed things along,
|
31
|
+
}, Thor::Shell::Color::YELLOW
|
32
|
+
|
33
|
+
exit unless yes? %Q{
|
34
|
+
If you want to speed things along, you should quit this tutorial (by saying 'no'),
|
35
|
+
and run it again with ./tutorial.thor --quick=yes.
|
36
|
+
|
37
|
+
Do you want to continue at this pace? (y/n) }, Thor::Shell::Color::GREEN
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
include Thor::Actions
|
42
|
+
include Rails::Generators::Actions
|
43
|
+
|
44
|
+
class Prerequisites < Thor::Group
|
45
|
+
class_option :quick, :default => false
|
46
|
+
include Thor::Actions
|
47
|
+
include Rails::Generators::Actions
|
48
|
+
|
49
|
+
def install_ruby
|
50
|
+
return if $quick
|
51
|
+
say %Q{
|
52
|
+
Obviously, if you can run this tutorial, you have already installed ruby.
|
53
|
+
}, Thor::Shell::Color::YELLOW
|
54
|
+
|
55
|
+
|
56
|
+
ruby_executable = run 'which ruby', :capture => true
|
57
|
+
|
58
|
+
say %Q{
|
59
|
+
You are running this using:
|
60
|
+
#{ruby_executable}
|
61
|
+
}, Thor::Shell::Color::YELLOW
|
62
|
+
|
63
|
+
if ruby_executable =~ /rvm/ or ruby_executable =~ /rbenv/ or ruby_executable =~ /home/ or ruby_Executable =~ /Users/
|
64
|
+
say %Q{
|
65
|
+
It looks like you're using rvm/rbenv/etc. (with a gemset?) We'll use this environment to build the application.
|
66
|
+
}, Thor::Shell::Color::YELLOW
|
67
|
+
|
68
|
+
else
|
69
|
+
|
70
|
+
say %Q{
|
71
|
+
We checked, and it looks like you might be using a system-wide ruby. We'd like to
|
72
|
+
suggest you use somethng like rvm [1], rbenv [2], etc to manage your ruby projects.
|
73
|
+
|
74
|
+
[1] http://rvm.io/
|
75
|
+
[2] https://github.com/sstephenson/rbenv/
|
76
|
+
}, Thor::Shell::Color::RED
|
77
|
+
|
78
|
+
exit unless yes? %Q{
|
79
|
+
You can continue and hope for the best, or go install one of these ruby managers, which may make your life easier.
|
80
|
+
|
81
|
+
Do you want to continue anyway? (y/n)
|
82
|
+
}, Thor::Shell::Color::GREEN
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
def install_bundler_and_rails
|
88
|
+
say %Q{
|
89
|
+
We're going to install some prerequisite gems in order to create our skeleton Rails application.
|
90
|
+
}, Thor::Shell::Color::YELLOW
|
91
|
+
run 'gem install bundler rails'
|
92
|
+
end
|
93
|
+
|
94
|
+
def new_rails_app
|
95
|
+
say %Q{
|
96
|
+
Now we'll create the application.
|
97
|
+
}, Thor::Shell::Color::YELLOW
|
98
|
+
run 'rails new hydra_tutorial_app'
|
99
|
+
run 'cd hydra_tutorial_app'
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
def out_of_the_box
|
104
|
+
return if $quick
|
105
|
+
say %Q{
|
106
|
+
Here's a chance to look around. You can see the structure of a Rails application.
|
107
|
+
./app
|
108
|
+
./config
|
109
|
+
./lib
|
110
|
+
Gemfile
|
111
|
+
}
|
112
|
+
|
113
|
+
ask %Q{
|
114
|
+
|
115
|
+
Hit ENTER when you're ready to continue.
|
116
|
+
}, Thor::Shell::Color::GREEN
|
117
|
+
end
|
118
|
+
|
119
|
+
# and then clean up some cruft
|
120
|
+
def remove_public_index
|
121
|
+
say %Q{
|
122
|
+
We'll now remove the Rails directions from the application.
|
123
|
+
}, Thor::Shell::Color::YELLOW
|
124
|
+
inside 'hydra_tutorial_app' do
|
125
|
+
remove_file 'public/index.html'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class BuildingABasicRailsApp < Thor::Group
|
131
|
+
include Thor::Actions
|
132
|
+
include Rails::Generators::Actions
|
133
|
+
|
134
|
+
def self.source_paths
|
135
|
+
[File.join($base_templates_path, "building_a_basic_rails_app")]
|
136
|
+
end
|
137
|
+
|
138
|
+
def notes
|
139
|
+
say %Q{
|
140
|
+
We're going to build an application to track (simplified) datasets and their metadata.
|
141
|
+
}, Thor::Shell::Color::YELLOW
|
142
|
+
end
|
143
|
+
|
144
|
+
def as_if_this_was_just_a_rails_applications
|
145
|
+
say %Q{
|
146
|
+
If we wanted to build a Rails application to do this, we would add some models and controllers.
|
147
|
+
|
148
|
+
Rails can help "scaffold" the application for us.
|
149
|
+
}, Thor::Shell::Color::YELLOW
|
150
|
+
|
151
|
+
generate 'scaffold', 'dataset', 'title', 'author', 'url', 'description:text'
|
152
|
+
rake 'db:migrate'
|
153
|
+
|
154
|
+
say %Q{
|
155
|
+
This created a Dataset model (in ./app/models/dataset.rb), a controller, and some views.
|
156
|
+
}, Thor::Shell::Color::YELLOW
|
157
|
+
|
158
|
+
ask %Q{
|
159
|
+
Take a look around. Hit ENTER when you're ready to continue.
|
160
|
+
}, Thor::Shell::Color::GREEN
|
161
|
+
end
|
162
|
+
|
163
|
+
def but_maybe_we_want_to_store_our_metadata_as_xml
|
164
|
+
say %Q{
|
165
|
+
But it turns out a relational database is not a great place to store complex metadata objects,
|
166
|
+
with nesting, hierarchy, repetition, etc like we often fine in the digital library world. We'd
|
167
|
+
also like to store and manage our data in an exchangeable form rather than a custom-built database.
|
168
|
+
|
169
|
+
In our world, we often find ourselves dealing with XML-based metadata. Fortunately, we have a gem called 'om' that can help us deal with XML metadata.
|
170
|
+
To start using it, we need to add it to our Gemfile.
|
171
|
+
}, Thor::Shell::Color::YELLOW
|
172
|
+
|
173
|
+
gem 'om'
|
174
|
+
run 'bundle install'
|
175
|
+
|
176
|
+
say %Q{
|
177
|
+
Now let's adapt our Dataset model to use OM. First we'll add some code that allows us to persist our
|
178
|
+
OM Documents on the filesystem (in db/datasets) and then add a simple OM terminology as a drop-in
|
179
|
+
replacement for the ActiveRecord scaffold object.
|
180
|
+
|
181
|
+
}, Thor::Shell::Color::YELLOW
|
182
|
+
|
183
|
+
run "mkdir db/datasets"
|
184
|
+
copy_file "om_record.rb", "app/models/om_record.rb"
|
185
|
+
|
186
|
+
say %Q{
|
187
|
+
Press 'd' to see the difference between the Rails version and the OM version of Dataset.
|
188
|
+
}, Thor::Shell::Color::YELLOW
|
189
|
+
|
190
|
+
copy_file "dataset_simple_om.rb", "app/models/dataset.rb"
|
191
|
+
|
192
|
+
ask %Q{
|
193
|
+
Take a look around.
|
194
|
+
|
195
|
+
Hit ENTER when you're ready to continue.
|
196
|
+
}, Thor::Shell::Color::GREEN
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
def stop_using_the_filesystem
|
202
|
+
say %Q{
|
203
|
+
Storing the documents on the filesystem has worked so far, but what if we wanted to start
|
204
|
+
managing whole objects (instead of XML documents), version datastream, keep checksums...
|
205
|
+
|
206
|
+
We use Fedora [3], and ActiveFedora to work with data in our repository. We also use Solr to
|
207
|
+
index and provide searching, faceting, etc for our content. For now, you can just concentrate on
|
208
|
+
Fedora. We'll have a section on Solr and discovery interfaces later.
|
209
|
+
|
210
|
+
[3] http://fedora-commons.org
|
211
|
+
}, Thor::Shell::Color::YELLOW
|
212
|
+
|
213
|
+
say %Q{
|
214
|
+
Fedora runs as a java servlet inside a container like Tomcat or Jetty. Hydra provides a bundled
|
215
|
+
version of Fedora and Solr for testing and development.
|
216
|
+
}, Thor::Shell::Color::YELLOW
|
217
|
+
|
218
|
+
say %Q{
|
219
|
+
We'll download a copy now. It may take awhile.
|
220
|
+
}, Thor::Shell::Color::YELLOW
|
221
|
+
unless File.exists? '../jetty'
|
222
|
+
git :clone => 'git://github.com/projecthydra/hydra-jetty.git ../jetty'
|
223
|
+
end
|
224
|
+
run 'cp -R ../jetty jetty'
|
225
|
+
# run 'rake hydra:jetty:config'
|
226
|
+
|
227
|
+
say %Q{
|
228
|
+
Now we're configure it and start the application.
|
229
|
+
}, Thor::Shell::Color::YELLOW
|
230
|
+
rake 'hydra:jetty:config'
|
231
|
+
|
232
|
+
copy_file 'solr.yml', 'config/solr.yml'
|
233
|
+
copy_file 'fedora.yml', 'config/fedora.yml'
|
234
|
+
|
235
|
+
say %Q{
|
236
|
+
And we'll use jettywrapper to help start and stop the service.
|
237
|
+
}, Thor::Shell::Color::YELLOW
|
238
|
+
|
239
|
+
gem 'jettywrapper'
|
240
|
+
run 'bundle install'
|
241
|
+
rake 'jetty:start'
|
242
|
+
|
243
|
+
say %Q{
|
244
|
+
Take a look around. Jetty should be running on port 8983. You can see the Fedora server at
|
245
|
+
|
246
|
+
http://localhost:8983/fedora/
|
247
|
+
|
248
|
+
And a Solr index at
|
249
|
+
|
250
|
+
http://localhost:8983/solr/development/admin/
|
251
|
+
}, Thor::Shell::Color::YELLOW
|
252
|
+
|
253
|
+
ask %Q{
|
254
|
+
Hit ENTER when you're ready to continue.
|
255
|
+
}, Thor::Shell::Color::GREEN
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
def convert_our_model_to_activefedora
|
260
|
+
say %Q{
|
261
|
+
We'll update our Dataset object to use ActiveFedora.
|
262
|
+
}, Thor::Shell::Color::YELLOW
|
263
|
+
|
264
|
+
gem 'active-fedora'
|
265
|
+
run 'bundle install'
|
266
|
+
copy_file "dataset_af_om.rb", "app/models/dataset.rb"
|
267
|
+
|
268
|
+
say %Q{
|
269
|
+
You should be able to create new dataset objects and see them updated in Fedora.
|
270
|
+
}, Thor::Shell::Color::YELLOW
|
271
|
+
|
272
|
+
ask %Q{
|
273
|
+
Hit ENTER when you're ready to continue.
|
274
|
+
}, Thor::Shell::Color::GREEN
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
class Application < Thor::Group
|
279
|
+
include Thor::Actions
|
280
|
+
include Rails::Generators::Actions
|
281
|
+
|
282
|
+
def self.source_paths
|
283
|
+
[File.join($base_templates_path, "application")]
|
284
|
+
end
|
285
|
+
|
286
|
+
# here are some gems that help
|
287
|
+
def add_blacklight_and_hydra
|
288
|
+
say %Q{
|
289
|
+
Eventually, common patterns get packaged up into new gems.
|
290
|
+
}, Thor::Shell::Color::YELLOW
|
291
|
+
|
292
|
+
say %Q{
|
293
|
+
We use blacklight to provide a search interface.
|
294
|
+
}, Thor::Shell::Color::YELLOW
|
295
|
+
|
296
|
+
gem 'blacklight'
|
297
|
+
run 'bundle install'
|
298
|
+
generate 'blacklight', '--devise'
|
299
|
+
|
300
|
+
say %Q{
|
301
|
+
And hydra-head bundles OM, ActiveFedora, etc for us. It also includes things like
|
302
|
+
gated discovery and permissions (through hydra-access-controls).
|
303
|
+
}, Thor::Shell::Color::YELLOW
|
304
|
+
|
305
|
+
gem 'hydra-head', "~> 4.1"
|
306
|
+
run 'bundle install'
|
307
|
+
generate 'hydra:head', 'User'
|
308
|
+
end
|
309
|
+
|
310
|
+
def rake_db_migrate
|
311
|
+
rake 'db:migrate'
|
312
|
+
rake 'db:test:prepare'
|
313
|
+
end
|
314
|
+
|
315
|
+
def install_hydra_jetty
|
316
|
+
if $quick # if we were in quick mode, we skipped this step from before..
|
317
|
+
say %Q{
|
318
|
+
Fedora runs as a java servlet inside a container like Tomcat or Jetty. Hydra provides a bundled
|
319
|
+
version of Fedora and Solr for testing and development.
|
320
|
+
}, Thor::Shell::Color::YELLOW
|
321
|
+
|
322
|
+
say %Q{
|
323
|
+
We'll download a copy now. It may take awhile.
|
324
|
+
}, Thor::Shell::Color::YELLOW
|
325
|
+
|
326
|
+
unless File.exists? '../jetty'
|
327
|
+
git :clone => 'git://github.com/projecthydra/hydra-jetty.git ../jetty'
|
328
|
+
end
|
329
|
+
run 'cp -R ../jetty jetty'
|
330
|
+
|
331
|
+
rake 'hydra:jetty:config'
|
332
|
+
|
333
|
+
gem 'jettywrapper'
|
334
|
+
run 'bundle install'
|
335
|
+
rake 'jetty:start'
|
336
|
+
else
|
337
|
+
|
338
|
+
rake 'jetty:stop'
|
339
|
+
rake 'hydra:jetty:config'
|
340
|
+
rake 'jetty:start'
|
341
|
+
end
|
342
|
+
|
343
|
+
end
|
344
|
+
|
345
|
+
def fixup_ui
|
346
|
+
remove_file 'app/assets/stylesheets/datasets.css.scss'
|
347
|
+
remove_file 'app/assets/stylesheets/scaffolds.css.scss'
|
348
|
+
end
|
349
|
+
|
350
|
+
def fixup_datasets
|
351
|
+
return if $quick
|
352
|
+
say %Q{
|
353
|
+
We need to make a couple of tweaks to our Dataset model and controller in order
|
354
|
+
to make it a Hydra-compliant object.
|
355
|
+
|
356
|
+
Because Hydra enforces access controls in the discovery layer (and, by default, no one
|
357
|
+
has access), we need to teach our model and controller about the Hydra rightsMetadata model
|
358
|
+
and have the controller tell the object who deposited it.
|
359
|
+
}, Thor::Shell::Color::YELLOW
|
360
|
+
|
361
|
+
copy_file "dataset_hydra_om.rb", "app/models/dataset.rb"
|
362
|
+
|
363
|
+
inject_into_class "app/controllers/datasets_controller.rb", 'DatasetsController' do
|
364
|
+
" include Hydra::AssetsControllerHelper\n"
|
365
|
+
end
|
366
|
+
|
367
|
+
insert_into_file "app/controllers/datasets_controller.rb", :after => "@dataset = Dataset.new(params[:dataset])\n" do
|
368
|
+
" apply_depositor_metadata(@dataset)\n"
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def lets_make_a_better_terminology
|
373
|
+
say %Q{
|
374
|
+
So far, we've been working with a made-up XML schema, however, in the real world, we're probably
|
375
|
+
dealing with more complex data in well-known standards like MODS.
|
376
|
+
|
377
|
+
Now we'll replace our custom schema with a basic MODS schema.
|
378
|
+
}, Thor::Shell::Color::YELLOW
|
379
|
+
copy_file "mods_desc_metadata.rb", "app/models/mods_desc_metadata.rb"
|
380
|
+
copy_file "dataset_hydra_mods_om.rb", "app/models/dataset.rb"
|
381
|
+
end
|
382
|
+
|
383
|
+
end
|
384
|
+
|
385
|
+
class MakeItNice < Thor::Group
|
386
|
+
include Thor::Actions
|
387
|
+
include Rails::Generators::Actions
|
388
|
+
|
389
|
+
def self.source_paths
|
390
|
+
[File.join($base_templates_path, "make_it_nice")]
|
391
|
+
end
|
392
|
+
|
393
|
+
# now we want our app to do stuff.. so lets enhance our old models
|
394
|
+
|
395
|
+
def some_better_views
|
396
|
+
|
397
|
+
end
|
398
|
+
|
399
|
+
def file_uploads
|
400
|
+
|
401
|
+
end
|
402
|
+
|
403
|
+
|
404
|
+
def sprinkle_some_css
|
405
|
+
|
406
|
+
end
|
407
|
+
|
408
|
+
end
|
409
|
+
|
410
|
+
class Tests < Thor::Group
|
411
|
+
include Thor::Actions
|
412
|
+
include Rails::Generators::Actions
|
413
|
+
|
414
|
+
# and write some tests
|
415
|
+
|
416
|
+
end
|
417
|
+
|
418
|
+
class InitialSteps < Thor::Group
|
419
|
+
include Thor::Actions
|
420
|
+
include Rails::Generators::Actions
|
421
|
+
|
422
|
+
# here are some steps you can do to get started
|
423
|
+
def create_a_user_account
|
424
|
+
|
425
|
+
end
|
426
|
+
|
427
|
+
def explore_the_application
|
428
|
+
run 'rails s'
|
429
|
+
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
|
434
|
+
class Cleanup < Thor::Group
|
435
|
+
include Thor::Actions
|
436
|
+
include Rails::Generators::Actions
|
437
|
+
|
438
|
+
# and write some tests
|
439
|
+
#
|
440
|
+
def stop_jetty
|
441
|
+
rake 'jetty:stop'
|
442
|
+
end
|
443
|
+
|
444
|
+
end
|
445
|
+
|
446
|
+
def prerequisites
|
447
|
+
Prerequisites.start
|
448
|
+
end
|
449
|
+
|
450
|
+
def building_a_basic_rails_app
|
451
|
+
return if $quick
|
452
|
+
|
453
|
+
inside 'hydra_tutorial_app' do
|
454
|
+
BuildingABasicRailsApp.start
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
def application
|
459
|
+
inside 'hydra_tutorial_app' do
|
460
|
+
Application.start
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
def make_it_nice
|
465
|
+
return if $quick
|
466
|
+
inside 'hydra_tutorial_app' do
|
467
|
+
MakeItNice.start
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
def tests
|
472
|
+
inside 'hydra_tutorial_app' do
|
473
|
+
Tests.start
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
def initial_steps
|
478
|
+
return if $quick
|
479
|
+
inside 'hydra_tutorial_app' do
|
480
|
+
InitialSteps.start
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
484
|
+
def cleanup
|
485
|
+
yes? "All Done?", Thor::Shell::Color::GREEN
|
486
|
+
inside 'hydra_tutorial_app' do
|
487
|
+
Cleanup.start
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
end
|
492
|
+
|
493
|
+
HydraTutorialApp.start
|