railswiki 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +185 -0
- data/Rakefile +24 -0
- data/app/assets/config/railswiki_manifest.js +2 -0
- data/app/assets/javascripts/railswiki/application.js +13 -0
- data/app/assets/javascripts/railswiki/histories.js +2 -0
- data/app/assets/javascripts/railswiki/invites.js +2 -0
- data/app/assets/javascripts/railswiki/pages.js +2 -0
- data/app/assets/javascripts/railswiki/sessions.js +2 -0
- data/app/assets/javascripts/railswiki/uploaded_files.js +2 -0
- data/app/assets/javascripts/railswiki/users.js +2 -0
- data/app/assets/stylesheets/railswiki/application.css +15 -0
- data/app/assets/stylesheets/railswiki/histories.css +4 -0
- data/app/assets/stylesheets/railswiki/invites.css +4 -0
- data/app/assets/stylesheets/railswiki/pages.scss +55 -0
- data/app/assets/stylesheets/railswiki/sessions.css +4 -0
- data/app/assets/stylesheets/railswiki/uploaded_files.scss +54 -0
- data/app/assets/stylesheets/railswiki/users.css +4 -0
- data/app/controllers/railswiki/application_controller.rb +126 -0
- data/app/controllers/railswiki/histories_controller.rb +48 -0
- data/app/controllers/railswiki/invites_controller.rb +61 -0
- data/app/controllers/railswiki/pages_controller.rb +141 -0
- data/app/controllers/railswiki/sessions_controller.rb +75 -0
- data/app/controllers/railswiki/uploaded_files_controller.rb +100 -0
- data/app/controllers/railswiki/users_controller.rb +55 -0
- data/app/helpers/railswiki/application_helper.rb +26 -0
- data/app/helpers/railswiki/histories_helper.rb +4 -0
- data/app/helpers/railswiki/invites_helper.rb +4 -0
- data/app/helpers/railswiki/pages_helper.rb +76 -0
- data/app/helpers/railswiki/sessions_helper.rb +4 -0
- data/app/helpers/railswiki/title_helper.rb +7 -0
- data/app/helpers/railswiki/uploaded_files_helper.rb +4 -0
- data/app/helpers/railswiki/users_helper.rb +4 -0
- data/app/helpers/railswiki/wiki_helper.rb +189 -0
- data/app/jobs/railswiki/application_job.rb +4 -0
- data/app/mailers/railswiki/application_mailer.rb +6 -0
- data/app/models/railswiki/application_record.rb +5 -0
- data/app/models/railswiki/history.rb +14 -0
- data/app/models/railswiki/invite.rb +20 -0
- data/app/models/railswiki/page.rb +56 -0
- data/app/models/railswiki/uploaded_file.rb +32 -0
- data/app/models/railswiki/user.rb +27 -0
- data/app/uploaders/railswiki/file_uploader.rb +56 -0
- data/app/views/layouts/railswiki/application.html.erb +25 -0
- data/app/views/railswiki/histories/index.html.erb +33 -0
- data/app/views/railswiki/histories/show.html.erb +17 -0
- data/app/views/railswiki/invites/_form.html.erb +38 -0
- data/app/views/railswiki/invites/index.html.erb +39 -0
- data/app/views/railswiki/invites/new.html.erb +7 -0
- data/app/views/railswiki/invites/show.html.erb +34 -0
- data/app/views/railswiki/pages/_form.html.erb +144 -0
- data/app/views/railswiki/pages/edit.html.erb +8 -0
- data/app/views/railswiki/pages/history.html.erb +11 -0
- data/app/views/railswiki/pages/index.html.erb +72 -0
- data/app/views/railswiki/pages/new.html.erb +7 -0
- data/app/views/railswiki/pages/show.html.erb +36 -0
- data/app/views/railswiki/sessions/no_invite.erb +7 -0
- data/app/views/railswiki/sessions/not_authorized.html.erb +12 -0
- data/app/views/railswiki/uploaded_files/_form.html.erb +31 -0
- data/app/views/railswiki/uploaded_files/_inline.html.erb +5 -0
- data/app/views/railswiki/uploaded_files/edit.html.erb +8 -0
- data/app/views/railswiki/uploaded_files/file_dialog.html.erb +11 -0
- data/app/views/railswiki/uploaded_files/image_dialog.html.erb +11 -0
- data/app/views/railswiki/uploaded_files/index.html.erb +36 -0
- data/app/views/railswiki/uploaded_files/new.html.erb +7 -0
- data/app/views/railswiki/uploaded_files/show.html.erb +29 -0
- data/app/views/railswiki/users/_form.html.erb +29 -0
- data/app/views/railswiki/users/edit.html.erb +8 -0
- data/app/views/railswiki/users/index.html.erb +37 -0
- data/app/views/railswiki/users/show.html.erb +59 -0
- data/app/views/shared/_formatting.md.erb +29 -0
- data/app/views/shared/_histories.html.erb +21 -0
- data/app/views/shared/_layout.html.erb +17 -0
- data/app/views/shared/_menu.html.erb +15 -0
- data/app/views/shared/_meta.html.erb +1 -0
- data/app/views/shared/_notices.html.erb +3 -0
- data/app/views/shared/_roles.html.erb +12 -0
- data/app/views/shared/_search.md.erb +5 -0
- data/config/initializers/carrierwave.rb +6 -0
- data/config/initializers/omniauth.rb +16 -0
- data/config/initializers/session_store.rb +1 -0
- data/config/routes.rb +25 -0
- data/db/migrate/20170420000841_create_railswiki_pages.rb +10 -0
- data/db/migrate/20170420010111_add_sessions_table.rb +12 -0
- data/db/migrate/20170420010147_create_railswiki_users.rb +14 -0
- data/db/migrate/20170420021039_add_lowercase_title_to_page.rb +5 -0
- data/db/migrate/20170420021840_create_railswiki_histories.rb +11 -0
- data/db/migrate/20170420235420_add_email_and_image_to_user.rb +8 -0
- data/db/migrate/20170421000333_add_last_login_to_user.rb +5 -0
- data/db/migrate/20170421010945_add_role_to_user.rb +7 -0
- data/db/migrate/20170421020932_create_railswiki_uploaded_files.rb +10 -0
- data/db/migrate/20170421030140_add_title_to_uploaded_file.rb +5 -0
- data/db/migrate/20170517224700_create_railswiki_invites.rb +12 -0
- data/db/migrate/20170517234452_add_role_to_invite.rb +5 -0
- data/db/migrate/20170622033540_set_all_mysql_tables_to_utf8.rb +54 -0
- data/lib/railswiki.rb +5 -0
- data/lib/railswiki/engine.rb +14 -0
- data/lib/railswiki/version.rb +3 -0
- data/lib/tasks/railswiki_tasks.rake +4 -0
- metadata +255 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require_dependency "redcarpet"
|
|
2
|
+
|
|
3
|
+
module Railswiki
|
|
4
|
+
module ApplicationHelper
|
|
5
|
+
include WikiHelper
|
|
6
|
+
include TitleHelper
|
|
7
|
+
|
|
8
|
+
def time_ago(time)
|
|
9
|
+
description = if time.present?
|
|
10
|
+
"#{time_ago_in_words(time)} ago"
|
|
11
|
+
else
|
|
12
|
+
"never!"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
content_tag "span", description, title: "#{time}", class: "time_ago"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def user_link(user)
|
|
19
|
+
if user.present?
|
|
20
|
+
link_to user.name, user
|
|
21
|
+
else
|
|
22
|
+
content_tag "i", "nobody!", class: "invalid_user"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module Railswiki
|
|
2
|
+
module PagesHelper
|
|
3
|
+
class SpecialPage
|
|
4
|
+
attr_reader :title, :author, :latest_version
|
|
5
|
+
|
|
6
|
+
def initialize(title:)
|
|
7
|
+
@title = title
|
|
8
|
+
@author = nil
|
|
9
|
+
@latest_version = nil
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def builtin_page?
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def content
|
|
17
|
+
case title
|
|
18
|
+
when "Special:Welcome"
|
|
19
|
+
"Welcome to your new wiki."
|
|
20
|
+
when "Special:Header"
|
|
21
|
+
<<-wiki_content
|
|
22
|
+
[[Home]]
|
|
23
|
+
{{Special:Search}}
|
|
24
|
+
wiki_content
|
|
25
|
+
when "Special:Search"
|
|
26
|
+
Railswiki::ApplicationController.render(
|
|
27
|
+
partial: "shared/search",
|
|
28
|
+
assigns: {},
|
|
29
|
+
formats: [:md]
|
|
30
|
+
)
|
|
31
|
+
when "Special:Footer"
|
|
32
|
+
<<-wiki_content
|
|
33
|
+
Copyright {{Special:Year}}
|
|
34
|
+
wiki_content
|
|
35
|
+
when "Special:Formatting"
|
|
36
|
+
Railswiki::ApplicationController.render(
|
|
37
|
+
partial: "shared/formatting",
|
|
38
|
+
assigns: {},
|
|
39
|
+
formats: [:md]
|
|
40
|
+
)
|
|
41
|
+
when "Special:Year"
|
|
42
|
+
"#{Time.now.year}"
|
|
43
|
+
else
|
|
44
|
+
"Unknown special page '#{title}'"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def special_page(title)
|
|
50
|
+
SpecialPage.new({
|
|
51
|
+
title: "Special:#{title}",
|
|
52
|
+
})
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def special_pages
|
|
56
|
+
[
|
|
57
|
+
special_page("Welcome"),
|
|
58
|
+
special_page("Header"),
|
|
59
|
+
special_page("Footer"),
|
|
60
|
+
special_page("Formatting"),
|
|
61
|
+
special_page("Search"),
|
|
62
|
+
special_page("Year")
|
|
63
|
+
]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def is_special_page?(page)
|
|
67
|
+
is_special_page_title?(page.title)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def is_special_page_title?(title)
|
|
71
|
+
return false if title.nil?
|
|
72
|
+
|
|
73
|
+
!! special_pages.select { |p| p.title.downcase == title.downcase }.first
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
require_dependency "redcarpet"
|
|
2
|
+
|
|
3
|
+
module Railswiki
|
|
4
|
+
module WikiHelper
|
|
5
|
+
include PagesHelper
|
|
6
|
+
|
|
7
|
+
def include_wiki(page_or_title)
|
|
8
|
+
if page_or_title.is_a?(Page)
|
|
9
|
+
page = page_or_title
|
|
10
|
+
else
|
|
11
|
+
page = select_page(page_or_title)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
return raw "<!-- no page #{page_or_title} -->" unless page
|
|
15
|
+
|
|
16
|
+
wiki_classes = "wiki-included wiki-#{classify_title(page.title)}"
|
|
17
|
+
|
|
18
|
+
return raw "<div class=\"#{wiki_classes}\">#{markdown_without_wrap.render page.content}</div>"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def include_wiki_class(page)
|
|
22
|
+
"<div>" + yield + "</div>"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def select_page(page_or_title)
|
|
26
|
+
@select_pages ||= Hash.new do |hash, ref|
|
|
27
|
+
# Don't try to include blank pages in here
|
|
28
|
+
return if ref.blank?
|
|
29
|
+
|
|
30
|
+
hash[ref] = Page.where(id: ref).
|
|
31
|
+
or(Page.where(title: [ref, unprettify_title(ref)]).
|
|
32
|
+
or(Page.where(lowercase_title: [ref.downcase, unprettify_title(ref.downcase), unprettify_slug(ref.downcase)]))).
|
|
33
|
+
first
|
|
34
|
+
hash[ref] ||= special_pages.select { |page| page.title.downcase == ref.downcase }.first
|
|
35
|
+
end
|
|
36
|
+
@select_pages[page_or_title]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def prettify_title(title)
|
|
40
|
+
title.gsub(/ /, "_")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def prettify_slug(title)
|
|
44
|
+
title.downcase.gsub(/ /, "-")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def unprettify_title(title)
|
|
48
|
+
title.present? ? title.gsub(/_/, " ") : nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def unprettify_slug(title)
|
|
52
|
+
title.present? ? title.gsub(/-/, " ") : nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def classify_title(title)
|
|
56
|
+
title.gsub(/[^a-z0-9\-_]+/i, "_")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def wiki_path(page, options = {})
|
|
60
|
+
page = "." if page == ""
|
|
61
|
+
|
|
62
|
+
if page.respond_to?(:title)
|
|
63
|
+
title_or_slug_path(page.title, options)
|
|
64
|
+
else
|
|
65
|
+
title_or_slug_path(page, options)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def title_or_slug_path(title, options)
|
|
70
|
+
if title == "Home" || title == "home"
|
|
71
|
+
return Rails.application.routes.url_helpers.root_path(options)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
if Railswiki::Engine.use_slugs
|
|
75
|
+
Rails.application.routes.url_helpers.slug_path(prettify_slug(title), options)
|
|
76
|
+
else
|
|
77
|
+
Railswiki::Engine.routes.url_helpers.title_path(prettify_title(title), options)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def markdown
|
|
82
|
+
@markdown ||= Redcarpet::Markdown.new(MarkdownRenderer.new(html_options), markdown_options)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def markdown_without_wrap
|
|
86
|
+
@markdown_without_wrap ||= Redcarpet::Markdown.new(MarkdownRendererWithoutWrap.new(), markdown_options)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def markdown_options
|
|
90
|
+
{
|
|
91
|
+
tables: true,
|
|
92
|
+
autolink: true,
|
|
93
|
+
no_intra_emphasis: true
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def html_options
|
|
98
|
+
{
|
|
99
|
+
}
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
class MarkdownRenderer < Redcarpet::Render::HTML
|
|
104
|
+
include WikiHelper
|
|
105
|
+
|
|
106
|
+
def preprocess(full_document)
|
|
107
|
+
code_blocks = []
|
|
108
|
+
|
|
109
|
+
# Strip out code blocks
|
|
110
|
+
full_document = full_document.gsub(/(```[^`]+?```)/im) do |match|
|
|
111
|
+
code_blocks << match
|
|
112
|
+
"__code_marker:#{code_blocks.length - 1}__"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Include templates {{template}}
|
|
116
|
+
full_document = full_document.gsub(/\{\{([^\}]+)\}\}/i) do |match|
|
|
117
|
+
template = select_page($1)
|
|
118
|
+
if template && template.content
|
|
119
|
+
# Because we are only including the raw content here, and not
|
|
120
|
+
# rendering the markdown before including it, it's not possible
|
|
121
|
+
# to have a stack overflow here. If this ever changes to
|
|
122
|
+
# somehow call preprocess() again, you MUST add a test to prevent
|
|
123
|
+
# infinite inclusion.
|
|
124
|
+
# It also means we don't need to `raw` the output.
|
|
125
|
+
"#{template.content}"
|
|
126
|
+
else
|
|
127
|
+
"*** Unknown template #{$1} ***"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Wiki links [[link|title|extra html]]
|
|
132
|
+
full_document = full_document.gsub(/\[\[([^\n]+?)\|([^\n]+?)\|([^\n]+?)\]\]/i) do |match|
|
|
133
|
+
"<a href=\"#{wiki_path($1)}\" #{$3}>#{$2}</a>"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Wiki links [[link|title]]
|
|
137
|
+
full_document = full_document.gsub(/\[\[([^\n]+?)\|([^\n]+?)\]\]/i) do |match|
|
|
138
|
+
"[#{$2}](#{wiki_path($1)})"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Wiki links [[link]]
|
|
142
|
+
full_document = full_document.gsub(/\[\[([^\n]+?)\]\]/i) do |match|
|
|
143
|
+
"[#{$1}](#{wiki_path($1)})"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Re-insert code blocks
|
|
147
|
+
full_document = full_document.gsub(/__code_marker:(\d+)__/) do |match|
|
|
148
|
+
code_blocks[$1.to_i]
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
full_document
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Image resizing as per https://github.com/vmg/redcarpet/issues/487
|
|
155
|
+
def image(link, title, alt_text)
|
|
156
|
+
if link =~ /^(.+?)\s*=+(\d+)(?:px|)$/
|
|
157
|
+
# 
|
|
158
|
+
# 
|
|
159
|
+
%(<img src="#{$1}" style="max-width: #{$2}px;" alt="#{alt_text}">)
|
|
160
|
+
elsif link =~ /^(.+?)\s*=+(\d+)(?:px|)x(\d+)(?:px|)$/
|
|
161
|
+
# 
|
|
162
|
+
%(<img src="#{$1}" style="max-width: #{$2}px; max-height: #{$3}px;" alt="#{alt_text}">)
|
|
163
|
+
elsif link =~ /^(.+?)\s*=+(\d+)%$/
|
|
164
|
+
# 
|
|
165
|
+
%(<img src="#{$1}" style="max-width: #{$2}%;" alt="#{alt_text}">)
|
|
166
|
+
elsif link =~ /^(.+?)\s*=+(\d+)%x(\d+)%$/
|
|
167
|
+
# 
|
|
168
|
+
%(<img src="#{$1}" style="max-width: #{$2}%; max-height: #{$3}%;" alt="#{alt_text}">)
|
|
169
|
+
else
|
|
170
|
+
%(<img src="#{link}" title="#{title}" alt="#{alt_text}">)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def postprocess(full_document)
|
|
175
|
+
full_document = full_document.gsub(/<p>= ([^ <>]+)<\/p>/i) do |match|
|
|
176
|
+
"<#{$1}>"
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
full_document
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Remove the <p> tags around the output as per https://github.com/vmg/redcarpet/issues/92
|
|
184
|
+
class MarkdownRendererWithoutWrap < MarkdownRenderer
|
|
185
|
+
def postprocess(full_document)
|
|
186
|
+
Regexp.new(/\A<p>(.*)<\/p>\Z/m).match(full_document)[1] rescue full_document
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "email_validator"
|
|
2
|
+
|
|
3
|
+
module Railswiki
|
|
4
|
+
class Invite < ApplicationRecord
|
|
5
|
+
belongs_to :inviting_user, class_name: "User"
|
|
6
|
+
belongs_to :invited_user, class_name: "User"
|
|
7
|
+
|
|
8
|
+
validates :email, presence: true, uniqueness: true, email: true
|
|
9
|
+
validates :inviting_user, presence: true
|
|
10
|
+
validates :role, presence: true, inclusion: { in: User::AVAILABLE_ROLES }
|
|
11
|
+
|
|
12
|
+
validate :user_cannot_already_be_registered
|
|
13
|
+
|
|
14
|
+
def user_cannot_already_be_registered
|
|
15
|
+
if accepted_at.nil? && User.where(email: email).any?
|
|
16
|
+
errors.add(:email, "is already registered as a user")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Railswiki
|
|
2
|
+
class Page < ApplicationRecord
|
|
3
|
+
attr_accessor :default_content
|
|
4
|
+
|
|
5
|
+
has_many :histories, dependent: :destroy
|
|
6
|
+
|
|
7
|
+
validates :title, presence: true, uniqueness: true
|
|
8
|
+
validates :lowercase_title, presence: true, uniqueness: true
|
|
9
|
+
|
|
10
|
+
before_validation :save_lowercase_title, on: [:create, :update]
|
|
11
|
+
validate :lowercase_title_must_equal_title
|
|
12
|
+
|
|
13
|
+
delegate :author, to: :latest_version, allow_nil: true
|
|
14
|
+
|
|
15
|
+
def content
|
|
16
|
+
latest_version.present? ? latest_version.body : default_content
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def latest_version
|
|
20
|
+
@latest_version ||= histories.where(id: latest_version_id).first
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def expose_json
|
|
24
|
+
{
|
|
25
|
+
id: id,
|
|
26
|
+
title: title,
|
|
27
|
+
updated_at: latest_version.created_at,
|
|
28
|
+
content: content
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def builtin_page?
|
|
33
|
+
false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.search(query)
|
|
37
|
+
if query
|
|
38
|
+
where("title LIKE :query COLLATE utf8_general_ci", query: "%#{query}%")
|
|
39
|
+
else
|
|
40
|
+
all
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def lowercase_title_must_equal_title
|
|
47
|
+
if title.downcase != lowercase_title.downcase
|
|
48
|
+
errors.add(:lowercase_title, "does not match the lowercase title")
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def save_lowercase_title
|
|
53
|
+
self.lowercase_title = self.title.downcase
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require_dependency 'carrierwave'
|
|
2
|
+
require_dependency 'carrierwave/orm/activerecord'
|
|
3
|
+
|
|
4
|
+
module Railswiki
|
|
5
|
+
class UploadedFile < ApplicationRecord
|
|
6
|
+
mount_uploader :file, FileUploader
|
|
7
|
+
|
|
8
|
+
belongs_to :user
|
|
9
|
+
|
|
10
|
+
validates :title, presence: true, uniqueness: true
|
|
11
|
+
validate :file_exists
|
|
12
|
+
|
|
13
|
+
delegate :content_type, to: :file
|
|
14
|
+
|
|
15
|
+
def file_url
|
|
16
|
+
file.url.sub "public/", ""
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def is_image?
|
|
20
|
+
file.content_type && MIME::Types[file.content_type].any? &&
|
|
21
|
+
MIME::Types[file.content_type].first.media_type == "image"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def file_exists
|
|
27
|
+
if file.file.nil?
|
|
28
|
+
errors.add(:file, "does not exist")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|