iconly 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +76 -0
- data/Rakefile +33 -0
- data/app/assets/config/iconly_manifest.js +2 -0
- data/app/assets/images/iconly/Noto-Sans-700.eot +0 -0
- data/app/assets/images/iconly/Noto-Sans-700.svg +336 -0
- data/app/assets/images/iconly/Noto-Sans-700.ttf +0 -0
- data/app/assets/images/iconly/Noto-Sans-700.woff +0 -0
- data/app/assets/images/iconly/Noto-Sans-700.woff2 +0 -0
- data/app/assets/images/iconly/Noto-Sans-regular.eot +0 -0
- data/app/assets/images/iconly/Noto-Sans-regular.svg +335 -0
- data/app/assets/images/iconly/Noto-Sans-regular.ttf +0 -0
- data/app/assets/images/iconly/Noto-Sans-regular.woff +0 -0
- data/app/assets/images/iconly/Noto-Sans-regular.woff2 +0 -0
- data/app/assets/images/iconly/Source-Sans-Pro-600.eot +0 -0
- data/app/assets/images/iconly/Source-Sans-Pro-600.svg +339 -0
- data/app/assets/images/iconly/Source-Sans-Pro-600.ttf +0 -0
- data/app/assets/images/iconly/Source-Sans-Pro-600.woff +0 -0
- data/app/assets/images/iconly/Source-Sans-Pro-600.woff2 +0 -0
- data/app/assets/images/iconly/Source-Sans-Pro-regular.eot +0 -0
- data/app/assets/images/iconly/Source-Sans-Pro-regular.svg +345 -0
- data/app/assets/images/iconly/Source-Sans-Pro-regular.ttf +0 -0
- data/app/assets/images/iconly/Source-Sans-Pro-regular.woff +0 -0
- data/app/assets/images/iconly/Source-Sans-Pro-regular.woff2 +0 -0
- data/app/assets/images/iconly/favicon.png +0 -0
- data/app/assets/images/iconly/iconly.eot +0 -0
- data/app/assets/images/iconly/iconly.svg +157 -0
- data/app/assets/images/iconly/iconly.ttf +0 -0
- data/app/assets/images/iconly/iconly.woff +0 -0
- data/app/assets/javascripts/iconly/application.js +24 -0
- data/app/assets/javascripts/iconly/iconly.coffee +5 -0
- data/app/assets/javascripts/iconly/jquery.sticky.js +268 -0
- data/app/assets/javascripts/iconly/package.coffee +25 -0
- data/app/assets/javascripts/iconly/project.coffee +68 -0
- data/app/assets/javascripts/iconly/scroller.coffee +17 -0
- data/app/assets/stylesheets/iconly/application.scss +21 -0
- data/app/assets/stylesheets/iconly/buttons.scss +314 -0
- data/app/assets/stylesheets/iconly/file_input.scss +25 -0
- data/app/assets/stylesheets/iconly/header.scss +179 -0
- data/app/assets/stylesheets/iconly/iconly.scss.erb +61 -0
- data/app/assets/stylesheets/iconly/layout.scss +269 -0
- data/app/assets/stylesheets/iconly/overrides.scss +58 -0
- data/app/assets/stylesheets/iconly/typography.scss.erb +48 -0
- data/app/controllers/iconly/application_controller.rb +8 -0
- data/app/controllers/iconly/packages_controller.rb +54 -0
- data/app/controllers/iconly/project_icons_controller.rb +24 -0
- data/app/controllers/iconly/projects_controller.rb +67 -0
- data/app/helpers/iconly/application_helper.rb +35 -0
- data/app/helpers/iconly/packages_helper.rb +29 -0
- data/app/helpers/iconly/project_icons_helper.rb +4 -0
- data/app/helpers/iconly/projects_helper.rb +4 -0
- data/app/helpers/iconly/sessions_helper.rb +43 -0
- data/app/jobs/iconly/application_job.rb +4 -0
- data/app/mailers/iconly/application_mailer.rb +6 -0
- data/app/models/iconly/application_record.rb +5 -0
- data/app/models/iconly/icon.rb +44 -0
- data/app/models/iconly/package.rb +5 -0
- data/app/models/iconly/project.rb +5 -0
- data/app/models/iconly/project/downloader.rb +50 -0
- data/app/models/iconly/project/font_generator.rb +65 -0
- data/app/models/iconly/project_icon.rb +23 -0
- data/app/models/iconly/user.rb +5 -0
- data/app/uploaders/iconly/svg_uploader.rb +51 -0
- data/app/views/iconly/packages/_form.html.erb +48 -0
- data/app/views/iconly/packages/new.html.erb +5 -0
- data/app/views/iconly/projects/_form.html.erb +25 -0
- data/app/views/iconly/projects/_packages.html.erb +91 -0
- data/app/views/iconly/projects/edit.html.erb +5 -0
- data/app/views/iconly/projects/index.html.erb +37 -0
- data/app/views/iconly/projects/new.html.erb +5 -0
- data/app/views/iconly/projects/show.html.erb +53 -0
- data/app/views/layouts/iconly/_footer.html.erb +18 -0
- data/app/views/layouts/iconly/_header.html.erb +89 -0
- data/app/views/layouts/iconly/application.html.erb +29 -0
- data/config/fontcustom/fontcustom_manifest.yml +53 -0
- data/config/fontcustom/templates/iconly.css +28 -0
- data/config/routes.rb +13 -0
- data/db/migrate/20170130210746_enable_uuid_extension.rb +5 -0
- data/db/migrate/20170130211049_create_iconly_users.rb +9 -0
- data/db/migrate/20170130220400_create_iconly_packages.rb +12 -0
- data/db/migrate/20170131002414_create_iconly_icons.rb +13 -0
- data/db/migrate/20170131081131_create_iconly_projects.rb +11 -0
- data/db/migrate/20170131084626_create_iconly_project_icons.rb +10 -0
- data/db/migrate/20170203144731_add_icon_count_to_packages.rb +5 -0
- data/lib/iconly.rb +22 -0
- data/lib/iconly/concerns/models/package.rb +41 -0
- data/lib/iconly/concerns/models/project.rb +27 -0
- data/lib/iconly/concerns/models/user.rb +23 -0
- data/lib/iconly/engine.rb +5 -0
- data/lib/iconly/version.rb +3 -0
- data/lib/iconly/zip_file_generator.rb +58 -0
- data/lib/tasks/iconly_tasks.rake +4 -0
- metadata +374 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
<footer class="app-footer">
|
2
|
+
<div class="container">
|
3
|
+
<div class="row">
|
4
|
+
<div class="col-md-8">
|
5
|
+
<a class="text-uppercase font-bold text-pale" href="/" title="Iconly">
|
6
|
+
<span>Icon</span><span class="text-default">ly</span>
|
7
|
+
</a>
|
8
|
+
© 2017. All rights reserved.
|
9
|
+
</div>
|
10
|
+
<div class="col-md-4 text-right">
|
11
|
+
<%= link_to Iconly::GITHUB_URL, class: 'btn btn-custom btn-white' do %>
|
12
|
+
<i class="iconly-github"></i>
|
13
|
+
Github
|
14
|
+
<% end %>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
</footer>
|
@@ -0,0 +1,89 @@
|
|
1
|
+
<nav class="app-header navbar navbar-toggleable-sm fixed-top">
|
2
|
+
<div class="container">
|
3
|
+
<button class="navbar-toggler btn btn-custom btn-default" type="button" data-toggle="collapse" data-target="#navbar-top-links" aria-controls="navbar-top-links" aria-expanded="false" aria-label="Toggle navigation">
|
4
|
+
Menu
|
5
|
+
</button>
|
6
|
+
|
7
|
+
<a class="navbar-brand" href="/" title="Iconly">
|
8
|
+
<span>Icon</span><span class="text-default">ly</span>
|
9
|
+
</a>
|
10
|
+
|
11
|
+
<% if signed_in? %>
|
12
|
+
<div class="row float-left">
|
13
|
+
<div class="col-md-6">
|
14
|
+
<div class="collapse navbar-collapse" id="navbar-top-links">
|
15
|
+
<ul class="nav navbar-nav first">
|
16
|
+
<li class="nav-item dropdown">
|
17
|
+
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
|
18
|
+
<span class="nav-link-in">Projects</span>
|
19
|
+
</a>
|
20
|
+
|
21
|
+
<div class="dropdown-menu">
|
22
|
+
<%= link_to iconly.projects_path, class: 'dropdown-item' do %>
|
23
|
+
<i class="iconly-files mr-05 text-primary"></i>
|
24
|
+
Projects
|
25
|
+
<% end %>
|
26
|
+
|
27
|
+
<div class="dropdown-divider"></div>
|
28
|
+
|
29
|
+
<% if current_user.projects.any? %>
|
30
|
+
<% current_user.projects.each do |project| %>
|
31
|
+
<%= link_to iconly.project_path(project), class: 'dropdown-item' do %>
|
32
|
+
<i class="iconly-file-check mr-05 text-primary"></i>
|
33
|
+
<%= project.name %>
|
34
|
+
<% end %>
|
35
|
+
<% end %>
|
36
|
+
|
37
|
+
<div class="dropdown-divider"></div>
|
38
|
+
<% end %>
|
39
|
+
<%= link_to iconly.new_project_path, class: 'dropdown-item' do %>
|
40
|
+
<i class="iconly-file-add mr-05 text-info"></i>
|
41
|
+
New Project
|
42
|
+
<% end %>
|
43
|
+
</div>
|
44
|
+
</li>
|
45
|
+
</ul>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
<div class="col-md-6">
|
49
|
+
<form role="search" class="form-inline app-search pull-xs-left" action="">
|
50
|
+
<i class="iconly-magnifier magnifier"></i>
|
51
|
+
<%= text_field_tag :q, params[:q], placeholder: 'Search fonts ...', class: 'form-control' %>
|
52
|
+
</form>
|
53
|
+
</div>
|
54
|
+
</div>
|
55
|
+
<% end %>
|
56
|
+
|
57
|
+
<ul class="nav navbar-nav navbar-user signed-in-<%= signed_in? %>">
|
58
|
+
<% if signed_in? %>
|
59
|
+
<li class="dropdown user clearfix">
|
60
|
+
<%= link_to iconly.new_package_path, class: 'float-left nav-link mr-3' do %>
|
61
|
+
<span class="btn btn-default nav-btn">
|
62
|
+
<i class="iconly-folder-plus mr-05"></i>
|
63
|
+
Import Icons
|
64
|
+
</span>
|
65
|
+
<% end %>
|
66
|
+
<a class="nav-link float-left dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
|
67
|
+
<span class="nav-link-in pull-xs-left img-<%= current_user.image_url.present? %>">
|
68
|
+
<%= image_tag(current_user.image_url) if current_user.image_url.present? %>
|
69
|
+
<i class="iconly-user placeholder"></i>
|
70
|
+
</span>
|
71
|
+
</a>
|
72
|
+
|
73
|
+
<div class="dropdown-menu dropdown-menu-right">
|
74
|
+
<%= link_to logout_path, method: :delete, class: "dropdown-item" do %>
|
75
|
+
<i class="iconly-power-switch text-danger mr-05"></i>
|
76
|
+
Log out
|
77
|
+
<% end %>
|
78
|
+
</div>
|
79
|
+
</li>
|
80
|
+
<% else %>
|
81
|
+
<li class="nav-item login">
|
82
|
+
<%= link_to login_path, class: 'nav-link' do %>
|
83
|
+
<span class="nav-link-in">Login</span>
|
84
|
+
<% end %>
|
85
|
+
</li>
|
86
|
+
<% end %>
|
87
|
+
</ul>
|
88
|
+
</div>
|
89
|
+
</nav>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= yield :title %> : Iconly</title>
|
5
|
+
<%= favicon_link_tag 'favicon.png' %>
|
6
|
+
|
7
|
+
<%= stylesheet_link_tag 'iconly/application', media: "all" %>
|
8
|
+
<%= javascript_include_tag 'iconly/application' %>
|
9
|
+
<%= csrf_meta_tags %>
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
<%= render 'layouts/iconly/header' %>
|
13
|
+
<%= render_flash %>
|
14
|
+
|
15
|
+
<div class="app-body">
|
16
|
+
<div class="container">
|
17
|
+
<%= yield %>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<%= render 'layouts/iconly/footer' %>
|
21
|
+
</div>
|
22
|
+
|
23
|
+
<%= yield :script %>
|
24
|
+
|
25
|
+
<script>
|
26
|
+
$(function() { iconly.start(); });
|
27
|
+
</script>
|
28
|
+
</body>
|
29
|
+
</html>
|
@@ -0,0 +1,53 @@
|
|
1
|
+
{
|
2
|
+
"checksum": {
|
3
|
+
"current": "",
|
4
|
+
"previous": ""
|
5
|
+
},
|
6
|
+
"fonts": [
|
7
|
+
"/var/folders/23/ntqhskc90_g352rdph_d_tdw0000gn/T/d20170210-77565-rddfvm/fonts/iconly.ttf",
|
8
|
+
"/var/folders/23/ntqhskc90_g352rdph_d_tdw0000gn/T/d20170210-77565-rddfvm/fonts/iconly.svg",
|
9
|
+
"/var/folders/23/ntqhskc90_g352rdph_d_tdw0000gn/T/d20170210-77565-rddfvm/fonts/iconly.woff",
|
10
|
+
"/var/folders/23/ntqhskc90_g352rdph_d_tdw0000gn/T/d20170210-77565-rddfvm/fonts/iconly.eot"
|
11
|
+
],
|
12
|
+
"glyphs": {
|
13
|
+
"facebook": {
|
14
|
+
"codepoint": 61696,
|
15
|
+
"source": "/var/folders/23/ntqhskc90_g352rdph_d_tdw0000gn/T/d20170210-77565-2t3ywc/facebook.svg"
|
16
|
+
},
|
17
|
+
"twitter": {
|
18
|
+
"codepoint": 61697,
|
19
|
+
"source": "/var/folders/23/ntqhskc90_g352rdph_d_tdw0000gn/T/d20170210-77565-2t3ywc/twitter.svg"
|
20
|
+
}
|
21
|
+
},
|
22
|
+
"options": {
|
23
|
+
"autowidth": false,
|
24
|
+
"config": false,
|
25
|
+
"css_selector": ".iconly-{{glyph}}",
|
26
|
+
"debug": false,
|
27
|
+
"font_ascent": 448,
|
28
|
+
"font_descent": 64,
|
29
|
+
"font_design_size": 16,
|
30
|
+
"font_em": 512,
|
31
|
+
"font_name": "iconly",
|
32
|
+
"force": false,
|
33
|
+
"input": {
|
34
|
+
"templates": "/Users/arti/work/lugo/iconly/iconly/config/fontcustom/templates",
|
35
|
+
"vectors": "/var/folders/23/ntqhskc90_g352rdph_d_tdw0000gn/T/d20170210-77565-2t3ywc"
|
36
|
+
},
|
37
|
+
"no_hash": true,
|
38
|
+
"output": {
|
39
|
+
"css": "/var/folders/23/ntqhskc90_g352rdph_d_tdw0000gn/T/d20170210-77565-rddfvm",
|
40
|
+
"fonts": "/var/folders/23/ntqhskc90_g352rdph_d_tdw0000gn/T/d20170210-77565-rddfvm/fonts",
|
41
|
+
"preview": "/var/folders/23/ntqhskc90_g352rdph_d_tdw0000gn/T/d20170210-77565-rddfvm/fonts"
|
42
|
+
},
|
43
|
+
"preprocessor_path": null,
|
44
|
+
"quiet": false,
|
45
|
+
"templates": [
|
46
|
+
"iconly.css"
|
47
|
+
],
|
48
|
+
"verbose": true
|
49
|
+
},
|
50
|
+
"templates": [
|
51
|
+
"/var/folders/23/ntqhskc90_g352rdph_d_tdw0000gn/T/d20170210-77565-rddfvm/iconly.css"
|
52
|
+
]
|
53
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
@font-face {
|
2
|
+
font-family: "<%= font_name %>";
|
3
|
+
src: url("fonts/<%= font_name %>.eot");
|
4
|
+
src: url("fonts/<%= font_name %>.eot?#iefix") format("embedded-opentype"),
|
5
|
+
url("fonts/<%= font_name %>.woff") format("woff"),
|
6
|
+
url("fonts/<%= font_name %>.ttf") format("truetype"),
|
7
|
+
url("fonts/<%= font_name %>.svg#<%= font_name %>") format("svg");
|
8
|
+
font-weight: normal;
|
9
|
+
font-style: normal;
|
10
|
+
}
|
11
|
+
|
12
|
+
[data-icon]:before { content: attr(data-icon); }
|
13
|
+
|
14
|
+
[data-icon]:before,
|
15
|
+
<%= glyph_selectors %> {
|
16
|
+
display: inline-block;
|
17
|
+
font-family: "<%= font_name %>";
|
18
|
+
font-style: normal;
|
19
|
+
font-weight: normal;
|
20
|
+
font-variant: normal;
|
21
|
+
line-height: 1;
|
22
|
+
text-decoration: inherit;
|
23
|
+
text-transform: none;
|
24
|
+
-moz-osx-font-smoothing: grayscale;
|
25
|
+
-webkit-font-smoothing: antialiased;
|
26
|
+
}
|
27
|
+
|
28
|
+
<%= glyphs %>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Iconly::Engine.routes.draw do
|
2
|
+
resources :projects do
|
3
|
+
post :generate_font, on: :member
|
4
|
+
end
|
5
|
+
|
6
|
+
resources :packages, only: %i(new create destroy) do
|
7
|
+
post :share, on: :member
|
8
|
+
end
|
9
|
+
|
10
|
+
resources :project_icons, only: %i(create destroy)
|
11
|
+
|
12
|
+
root 'projects#index'
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateIconlyPackages < ActiveRecord::Migration[5.0]
|
2
|
+
def change
|
3
|
+
create_table :iconly_packages, id: :uuid do |t|
|
4
|
+
t.uuid :user_id, null: false, index: true, foreign_key: true
|
5
|
+
t.string :name
|
6
|
+
t.boolean :shared
|
7
|
+
t.string :slug
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateIconlyIcons < ActiveRecord::Migration[5.0]
|
2
|
+
def change
|
3
|
+
create_table :iconly_icons, id: :uuid do |t|
|
4
|
+
t.uuid :package_id, null: false, index: true, foreign_key: true
|
5
|
+
t.string :name
|
6
|
+
t.string :slug
|
7
|
+
t.string :svg
|
8
|
+
t.text :contents
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class CreateIconlyProjectIcons < ActiveRecord::Migration[5.0]
|
2
|
+
def change
|
3
|
+
create_table :iconly_project_icons, id: :uuid do |t|
|
4
|
+
t.uuid :project_id, null: false, index: true, foreign_key: true
|
5
|
+
t.uuid :icon_id, null: false, index: true, foreign_key: true
|
6
|
+
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
data/lib/iconly.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'friendly_id'
|
2
|
+
require 'carrierwave'
|
3
|
+
require 'fontcustom'
|
4
|
+
require 'sass-rails'
|
5
|
+
require 'jquery-rails'
|
6
|
+
require 'turbolinks'
|
7
|
+
require 'bootstrap'
|
8
|
+
require 'rails-assets-tether'
|
9
|
+
require 'iconly/engine'
|
10
|
+
require 'iconly/zip_file_generator'
|
11
|
+
require 'iconly/concerns/models/user'
|
12
|
+
require 'iconly/concerns/models/package'
|
13
|
+
require 'iconly/concerns/models/project'
|
14
|
+
|
15
|
+
module Iconly
|
16
|
+
GITHUB_URL = 'https://github.com/lugolabs/iconly'.freeze
|
17
|
+
|
18
|
+
mattr_accessor :logout_path,
|
19
|
+
:login_path,
|
20
|
+
:svg_folder,
|
21
|
+
:downloads_folder
|
22
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Iconly
|
2
|
+
module Concerns
|
3
|
+
module Models
|
4
|
+
module Package
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
belongs_to :user, class_name: 'User'
|
9
|
+
has_many :icons, dependent: :destroy
|
10
|
+
|
11
|
+
attr_accessor :icon_files, :icon_files_required
|
12
|
+
|
13
|
+
extend FriendlyId
|
14
|
+
friendly_id :name, use: [:slugged, :scoped], scope: :user
|
15
|
+
|
16
|
+
validates :name, presence: true, uniqueness: { scope: :user }
|
17
|
+
validates :icon_files, presence: true, if: :icon_files_required
|
18
|
+
|
19
|
+
after_create :generate_icons, if: :icon_files_required
|
20
|
+
|
21
|
+
scope :shared, -> { where(shared: true) }
|
22
|
+
scope :shared_or_owned_by, ->(user_id) { where(user_id: user_id).or(shared) }
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def generate_icons
|
28
|
+
icon_files.each do |file|
|
29
|
+
name = file.original_filename.split('.')[0..-2].join('.')
|
30
|
+
icons.create!(name: name, svg: file, contents: file.read)
|
31
|
+
end
|
32
|
+
update(icon_count: icon_files.size)
|
33
|
+
end
|
34
|
+
|
35
|
+
def should_generate_new_friendly_id?
|
36
|
+
name_changed?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Iconly
|
2
|
+
module Concerns
|
3
|
+
module Models
|
4
|
+
module Project
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
belongs_to :user, class_name: 'User'
|
9
|
+
has_many :project_icons
|
10
|
+
has_many :icons, through: :project_icons
|
11
|
+
|
12
|
+
extend FriendlyId
|
13
|
+
friendly_id :name, use: [:slugged, :scoped], scope: :user
|
14
|
+
|
15
|
+
scope :owned_by, ->(owner_id) { where('iconly_projects.user_id' => owner_id) }
|
16
|
+
scope :without_icons, -> { where.not(id: ProjectIcon.select(:project_id)) }
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def should_generate_new_friendly_id?
|
22
|
+
name_changed?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Iconly
|
2
|
+
module Concerns
|
3
|
+
module Models
|
4
|
+
module User
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
has_many :packages
|
9
|
+
has_many :projects
|
10
|
+
|
11
|
+
after_create :generate_project
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def generate_project
|
17
|
+
return if projects.any?
|
18
|
+
projects.create!(name: 'Untitled Project')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|