openstax_api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +73 -0
  4. data/Rakefile +22 -0
  5. data/app/controllers/openstax/api/v1/api_controller.rb +75 -0
  6. data/app/controllers/openstax/api/v1/oauth_based_api_controller.rb +17 -0
  7. data/app/models/openstax/api/api_user.rb +82 -0
  8. data/app/representers/openstax/api/v1/representable_schema_printer.rb +85 -0
  9. data/lib/openstax_api/constraints.rb +21 -0
  10. data/lib/openstax_api/doorkeeper_extensions.rb +22 -0
  11. data/lib/openstax_api/engine.rb +20 -0
  12. data/lib/openstax_api/route_extensions.rb +17 -0
  13. data/lib/openstax_api/version.rb +5 -0
  14. data/lib/openstax_api.rb +8 -0
  15. data/spec/app/controllers/openstax/api/v1/api_controller_spec.rb +11 -0
  16. data/spec/app/controllers/openstax/api/v1/oauth_based_api_controller_spec.rb +11 -0
  17. data/spec/app/models/openstax/api/api_user_spec.rb +47 -0
  18. data/spec/app/representers/openstax/api/v1/representable_schema_printer_spec.rb +19 -0
  19. data/spec/dummy/README.md +1 -0
  20. data/spec/dummy/Rakefile +7 -0
  21. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  22. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  23. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  24. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  25. data/spec/dummy/app/models/user.rb +2 -0
  26. data/spec/dummy/app/representers/user_representer.rb +8 -0
  27. data/spec/dummy/config/application.rb +53 -0
  28. data/spec/dummy/config/boot.rb +10 -0
  29. data/spec/dummy/config/database.yml +25 -0
  30. data/spec/dummy/config/environment.rb +5 -0
  31. data/spec/dummy/config/environments/development.rb +29 -0
  32. data/spec/dummy/config/environments/production.rb +69 -0
  33. data/spec/dummy/config/environments/test.rb +35 -0
  34. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  35. data/spec/dummy/config/initializers/doorkeeper.rb +75 -0
  36. data/spec/dummy/config/initializers/inflections.rb +15 -0
  37. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  38. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  39. data/spec/dummy/config/initializers/session_store.rb +8 -0
  40. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  41. data/spec/dummy/config/locales/en.yml +5 -0
  42. data/spec/dummy/config/routes.rb +2 -0
  43. data/spec/dummy/config.ru +4 -0
  44. data/spec/dummy/db/development.sqlite3 +0 -0
  45. data/spec/dummy/db/migrate/0_create_doorkeeper_tables.rb +42 -0
  46. data/spec/dummy/db/migrate/1_create_users.rb +10 -0
  47. data/spec/dummy/db/schema.rb +62 -0
  48. data/spec/dummy/db/test.sqlite3 +0 -0
  49. data/spec/dummy/log/development.log +541 -0
  50. data/spec/dummy/log/test.log +3183 -0
  51. data/spec/dummy/public/404.html +26 -0
  52. data/spec/dummy/public/422.html +26 -0
  53. data/spec/dummy/public/500.html +25 -0
  54. data/spec/dummy/public/favicon.ico +0 -0
  55. data/spec/dummy/script/rails +6 -0
  56. data/spec/lib/openstax_api/constraints_spec.rb +74 -0
  57. data/spec/lib/openstax_api/doorkeeper_extensions_spec.rb +17 -0
  58. data/spec/lib/openstax_api/route_extensions_spec.rb +21 -0
  59. data/spec/spec_helper.rb +18 -0
  60. metadata +248 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e65fff56b84dbf775bc833cac2d8c0d47ac17071
4
+ data.tar.gz: 50a0a75083a94728f96ae03850976d69591cfa3c
5
+ SHA512:
6
+ metadata.gz: 1ee105cdac7c958f73f350386dffad9440b7de73a860f607a5c7df4ef06aec8cfb113a974db0c5e894cc09a2e687f3c66dac4881e25c684b008dc1bd679bee67
7
+ data.tar.gz: d4e10fbe22973ad8d80143ccbf7e6013064ca6ec9f6792d2612043994fa1521f028c61e38e54db80269d7df9f730efaa4c019979678a4e904539ecd0b1ddab9b
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # openstax_api
2
+
3
+ API utilities for OpenStax products and tools.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```rb
10
+ gem 'openstax_api'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```sh
16
+ $ bundle
17
+ ```
18
+
19
+ ## Included classes
20
+
21
+ This gem includes the following classes, all under the OpenStax::Api namespace:
22
+
23
+ ### Controllers
24
+
25
+ `ApiController`
26
+
27
+ `OauthBasedApiController`
28
+
29
+ Your API controllers should inherit from those classes.
30
+
31
+ ### Models
32
+
33
+ `ApiUser`
34
+
35
+ This is the class of someone using the API, which can either be a (signed in) user, a doorkeeper application, or a combination of both.
36
+
37
+ ## Doorkeeper Extensions
38
+
39
+ This gem also adds the following methods to Doorkeeper::Application:
40
+
41
+ `is_human?`, `is_application?` and `is_admin?`
42
+
43
+ ## Route simplification
44
+
45
+ Finally, this gem allows API routes to be simplified by using the api method, like so:
46
+
47
+ ```rb
48
+ apipie
49
+
50
+ get 'api', to: 'static_pages#api'
51
+
52
+ api :v1, true do
53
+ get '/your_api_routes_go_here'
54
+ end
55
+ ```
56
+
57
+ The api route method takes a version argument and a boolean.
58
+ If the boolean is true, that version is the default (latest) and will always match the Accept header. It should be defined last, as any API route after that will be ignored.
59
+
60
+ ## Testing
61
+
62
+ From the gem's main folder, run `bundle`, and then `rake` to run all the specs.
63
+
64
+ ## Contributing
65
+
66
+ 1. Fork it
67
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
68
+ 3. Create specs for your feature
69
+ 4. Ensure that all specs pass
70
+ 5. Commit your changes (`git commit -am 'Add some feature'`)
71
+ 6. Push to the branch (`git push origin my-new-feature`)
72
+ 7. Create new pull request
73
+
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env rake
2
+ # http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
10
+ load 'rails/tasks/engine.rake'
11
+
12
+ Bundler::GemHelper.install_tasks
13
+
14
+ Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
15
+
16
+ require 'rspec/core'
17
+ require 'rspec/core/rake_task'
18
+
19
+ desc 'Run all specs in spec directory (excluding plugin specs)'
20
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
21
+
22
+ task :default => :spec
@@ -0,0 +1,75 @@
1
+ require 'roar-rails'
2
+
3
+ module OpenStax
4
+ module Api
5
+ module V1
6
+
7
+ class ApiController < ::ApplicationController
8
+
9
+ include Roar::Rails::ControllerAdditions
10
+
11
+ fine_print_skip_signatures(:general_terms_of_use,
12
+ :privacy_policy) \
13
+ if respond_to? :fine_print_skip_signatures
14
+
15
+ skip_protect_beta if respond_to? :skip_protect_beta
16
+
17
+ skip_before_filter :authenticate_user!
18
+
19
+ respond_to :json
20
+ rescue_from Exception, :with => :rescue_from_exception
21
+
22
+ def self.api_example(options={})
23
+ return if Rails.env.test?
24
+ raise IllegalArgument, "must supply a :url parameter" if !options[:url_base]
25
+
26
+ url_base = options[:url_base].is_a?(Symbol) ?
27
+ UrlGenerator.new.send(options[:url_base], protocol: 'https') :
28
+ options[:url_base].to_s
29
+
30
+ "#{url_base}/#{options[:url_end] || ''}"
31
+ end
32
+
33
+ def self.json_schema(representer, options={})
34
+ RepresentableSchemaPrinter.json(representer, options)
35
+ end
36
+
37
+ protected
38
+
39
+ def rescue_from_exception(exception)
40
+ # See https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L453 for error names/symbols
41
+ error = :internal_server_error
42
+ notify = true
43
+
44
+ case exception
45
+ when SecurityTransgression
46
+ error = :forbidden
47
+ notify = false
48
+ when ActiveRecord::RecordNotFound,
49
+ ActionController::RoutingError,
50
+ ActionController::UnknownController,
51
+ AbstractController::ActionNotFound
52
+ error = :not_found
53
+ notify = false
54
+ end
55
+
56
+ if notify
57
+ # Not yet in OSU
58
+ =begin
59
+ ExceptionNotifier.notify_exception(
60
+ exception,
61
+ env: request.env,
62
+ data: { message: "An exception occurred" }
63
+ )
64
+ =end
65
+ Rails.logger.error("An exception occurred: #{exception.message}\n\n#{exception.backtrace.join("\n")}") \
66
+ end
67
+
68
+ head error
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,17 @@
1
+ module OpenStax
2
+ module Api
3
+ module V1
4
+
5
+ class OauthBasedApiController < ApiController
6
+
7
+ respond_to :json
8
+
9
+ def current_user
10
+ @current_api_user ||= ApiUser.new(doorkeeper_token, lambda { super })
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,82 @@
1
+ # A "user" (lowercase 'u') of an API can take one of several forms.
2
+ #
3
+ # 1. It can just be a User (capital 'U') based on session data (e.g.
4
+ # someone who logs into this site and then uses this site's Backbone
5
+ # interface).
6
+ # 2. It can be a combination of a Doorkeeper Application and a User,
7
+ # given via OAuth's Authorization or Implicit flows.
8
+ # 3. It can just be a Doorkeeper Application, given through OAuth's
9
+ # Client Credentials flow.
10
+ #
11
+ # This API class gives us a way to abstract out these cases and also
12
+ # gives us accessors to get the Application and User objects, if available.
13
+
14
+ module OpenStax
15
+ module Api
16
+ class ApiUser
17
+
18
+ def initialize(doorkeeper_token, non_doorkeeper_user_proc)
19
+ # If we have a doorkeeper_token, derive the Application and User
20
+ # from it. If not, we're in case #1 above and the User should be
21
+ # retrieved from the alternative proc provided in arguments and
22
+ # there is no application.
23
+ #
24
+ # In both cases, don't actually retrieve any data -- just save off
25
+ # procs that can get it for us. This could save us some queries.
26
+
27
+ if doorkeeper_token
28
+ @application_proc = lambda { doorkeeper_token.application }
29
+ @user_proc = lambda {
30
+ doorkeeper_token.resource_owner_id ?
31
+ User.find(doorkeeper_token.resource_owner_id) :
32
+ nil
33
+ }
34
+ else
35
+ @user_proc = non_doorkeeper_user_proc
36
+ @application_proc = lambda { nil }
37
+ end
38
+ end
39
+
40
+ # Returns a Doorkeeper::Application or nil
41
+ # TODO should we have a NoApplication like NoUser (or maybe should
42
+ # NoUser just be replaced with nil)
43
+ def application
44
+ @application ||= @application_proc.call
45
+ end
46
+
47
+ # Can return an instance of User, AnonymousUser, or nil
48
+ def human_user
49
+ @user ||= @user_proc.call
50
+ end
51
+
52
+ ##########################
53
+ # Access Control Helpers #
54
+ ##########################
55
+
56
+ def can_do?(action, resource)
57
+ OSU::AccessPolicy.action_allowed?(action, self, resource)
58
+ end
59
+
60
+ def can_read?(resource)
61
+ can_do?(:read, resource)
62
+ end
63
+
64
+ def can_create?(resource)
65
+ can_do?(:create, resource)
66
+ end
67
+
68
+ def can_update?(resource)
69
+ can_do?(:update, resource)
70
+ end
71
+
72
+ def can_destroy?(resource)
73
+ can_do?(:destroy, resource)
74
+ end
75
+
76
+ def can_sort?(resource)
77
+ can_do?(:sort, resource)
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,85 @@
1
+ module OpenStax
2
+ module Api
3
+ module V1
4
+ class RepresentableSchemaPrinter
5
+
6
+ def self.json(representer, options={})
7
+ options[:include] ||= [:readable, :writeable]
8
+ options[:indent] ||= ' '
9
+
10
+ definitions = {}
11
+
12
+ schema = json_schema(representer, definitions, options)
13
+ schema[:definitions] = definitions
14
+
15
+ json_string = JSON.pretty_generate(schema, {indent: options[:indent]})
16
+
17
+ "\nSchema {##{SecureRandom.hex(4)} .schema}\n------\n" +
18
+ "<pre class='code'>\n#{json_string}\n</pre>\n"
19
+ end
20
+
21
+ protected
22
+
23
+ def self.json_schema(representer, definitions, options={})
24
+ schema = {
25
+ # id: schema_id(representer),
26
+ # title: schema_title(representer),
27
+ type: "object",
28
+ properties: {},
29
+ required: []
30
+ # :$schema => "http://json-schema.org/draft-04/schema#"
31
+ }
32
+
33
+ representer.representable_attrs.each do |attr|
34
+ schema_info = attr.options[:schema_info] || {}
35
+
36
+ schema[:required].push(attr.name) if schema_info[:required]
37
+
38
+ next unless [options[:include]].flatten.any?{|inc| attr.send(inc.to_s+"?") || schema_info[:required]}
39
+
40
+ attr_info = {}
41
+
42
+ if attr.options[:collection]
43
+ attr_info[:type] = "array"
44
+ else
45
+ attr_info[:type] = attr.options[:type].to_s.downcase if attr.options[:type]
46
+ end
47
+
48
+ schema_info.each do |key, value|
49
+ next if [:required].include?(key)
50
+ value = value.to_s.downcase if key == :type
51
+ attr_info[key] = value
52
+ end
53
+
54
+ decorator = attr.options[:decorator].try(:is_a?, Proc) ? nil : attr.options[:decorator]
55
+
56
+ if decorator
57
+ relative_schema_id(decorator).tap do |id|
58
+ attr_info[:$ref] = "#/definitions/#{id}"
59
+ definitions[id] ||= json_schema(decorator, definitions, options)
60
+ end
61
+ end
62
+
63
+ schema[:properties][attr.name.to_sym] = attr_info
64
+ end
65
+
66
+ schema
67
+ end
68
+
69
+ def self.schema_title(representer)
70
+ representer.name.gsub(/Representer/,'')
71
+ end
72
+
73
+ def self.schema_id(representer)
74
+ "http://#{OpenStax::Api::Engine::MAIN_APP_NAME.to_s}.openstax.org/" +
75
+ "#{schema_title(representer).downcase.gsub(/::/,'/')}"
76
+ end
77
+
78
+ def self.relative_schema_id(representer)
79
+ representer.name.gsub(/Representer/,'').downcase.gsub(/::/,'/')
80
+ end
81
+
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,21 @@
1
+ module OpenStax
2
+ module Api
3
+ class Constraints
4
+ cattr_accessor :main_app_name
5
+
6
+ def initialize(options)
7
+ @version = options[:version]
8
+ @default = options[:default]
9
+ end
10
+
11
+ def api_accept_header
12
+ self.main_app_name ||= OpenStax::Api::Engine::MAIN_APP_NAME.underscore
13
+ "application/vnd.#{self.main_app_name}.openstax.#{@version.to_s}"
14
+ end
15
+
16
+ def matches?(req)
17
+ @default || req.headers['Accept'].try(:include?, api_accept_header)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ module OpenStax
2
+ module Api
3
+ module DoorkeeperExtensions
4
+ # Add some fields to Doorkeeper::Application
5
+ def is_human?
6
+ false
7
+ end
8
+
9
+ def is_application?
10
+ true
11
+ end
12
+
13
+ def is_admin?
14
+ false
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ OpenStax::Api::Engine.config.after_initialize do
21
+ Doorkeeper::Application.send :include, OpenStax::Api::DoorkeeperExtensions
22
+ end
@@ -0,0 +1,20 @@
1
+ module OpenStax
2
+ module Api
3
+ class Engine < ::Rails::Engine
4
+ isolate_namespace OpenStax::Api
5
+
6
+ config.after_initialize do
7
+ MAIN_APP_NAME = ::Rails.application.class.parent_name
8
+ end
9
+
10
+ config.generators do |g|
11
+ g.test_framework :rspec, :fixture => false
12
+ g.fixture_replacement :factory_girl, :dir => 'spec/factories'
13
+ end
14
+
15
+ ActiveSupport::Inflector.inflections do |inflect|
16
+ inflect.acronym 'OpenStax'
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ require 'openstax_api/constraints'
2
+
3
+ module OpenStax
4
+ module Api
5
+ module RouteExtensions
6
+ def api(version = :v1, default = false)
7
+ constraints = Constraints.new(version: version, default: default)
8
+ namespace :api, defaults: {format: 'json'} do
9
+ scope(module: version,
10
+ constraints: constraints) { yield }
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ ActionDispatch::Routing::Mapper.send :include, OpenStax::Api::RouteExtensions
@@ -0,0 +1,5 @@
1
+ module OpenStax
2
+ module Api
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ require 'openstax_api/engine'
2
+ require 'openstax_api/doorkeeper_extensions'
3
+ require 'openstax_api/route_extensions'
4
+
5
+ module OpenStax
6
+ module Api
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ module OpenStax
4
+ module Api
5
+ module V1
6
+ describe ApiController do
7
+ # Nothing to test yet
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ module OpenStax
4
+ module Api
5
+ module V1
6
+ describe OauthBasedApiController do
7
+ # Nothing to test yet
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ module OpenStax
4
+ module Api
5
+ describe ApiUser do
6
+ let(:user) { User.create }
7
+ let(:application) { double('Doorkeeper::Application') }
8
+ let(:doorkeeper_token) { double('Doorkeeper::AccessToken') }
9
+ let(:non_doorkeeper_user_proc) { lambda { user } }
10
+
11
+ context 'human user' do
12
+ let(:api_user) { ApiUser.new(nil, non_doorkeeper_user_proc) }
13
+
14
+ it 'has a human_user but no application' do
15
+ expect(api_user.application).to be_nil
16
+ expect(api_user.human_user).to eq(user)
17
+ end
18
+ end
19
+
20
+ context 'application with human user' do
21
+ let(:api_user) { ApiUser.new(doorkeeper_token,
22
+ non_doorkeeper_user_proc) }
23
+
24
+ it 'has a human_user and an application' do
25
+ doorkeeper_token.stub(:application).and_return(application)
26
+ doorkeeper_token.stub(:resource_owner_id).and_return(user.id)
27
+
28
+ expect(api_user.application).to eq(application)
29
+ expect(api_user.human_user).to eq(user)
30
+ end
31
+ end
32
+
33
+ context 'application only' do
34
+ let(:api_user) { ApiUser.new(doorkeeper_token,
35
+ non_doorkeeper_user_proc) }
36
+
37
+ it 'has an application but no human_user' do
38
+ doorkeeper_token.stub(:application).and_return(application)
39
+ doorkeeper_token.stub(:resource_owner_id).and_return(nil)
40
+
41
+ expect(api_user.application).to eq(application)
42
+ expect(api_user.human_user).to be_nil
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ module OpenStax
4
+ module Api
5
+ module V1
6
+ describe RepresentableSchemaPrinter do
7
+ it 'must print model schemas' do
8
+ schema = RepresentableSchemaPrinter.json(UserRepresenter)
9
+ expect(schema).to include('Schema')
10
+ expect(schema).to include('.schema')
11
+ expect(schema).to include('------')
12
+ expect(schema).to include("<pre class='code'>")
13
+ expect(schema).to include("{\n \"type\": \"object\",\n \"properties\": {\n \"username\": {\n },\n \"password_hash\": {\n }\n },\n \"required\": [\n\n ],\n \"definitions\": {\n }\n}")
14
+ expect(schema).to include('</pre>')
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1 @@
1
+ Dummy application used to test the openstax_api gem.
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
3
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
+
5
+ require File.expand_path('../config/application', __FILE__)
6
+
7
+ Dummy::Application.load_tasks
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ class User < ActiveRecord::Base
2
+ end
@@ -0,0 +1,8 @@
1
+ require 'representable/json'
2
+
3
+ module UserRepresenter
4
+ include Roar::Representer::JSON
5
+
6
+ property :username
7
+ property :password_hash
8
+ end