comable-core 0.6.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/Rakefile +97 -0
- data/app/assets/javascripts/comable/application.js +13 -0
- data/app/assets/stylesheets/comable/application.css +13 -0
- data/app/controllers/concerns/comable/permitted_attributes.rb +15 -0
- data/app/helpers/comable/application_helper.rb +84 -0
- data/app/helpers/comable/products_helper.rb +82 -0
- data/app/mailers/comable/order_mailer.rb +18 -0
- data/app/models/comable/ability.rb +18 -0
- data/app/models/comable/address.rb +39 -0
- data/app/models/comable/category.rb +72 -0
- data/app/models/comable/image.rb +15 -0
- data/app/models/comable/order.rb +121 -0
- data/app/models/comable/order/associations.rb +22 -0
- data/app/models/comable/order/callbacks.rb +43 -0
- data/app/models/comable/order/morrisable.rb +20 -0
- data/app/models/comable/order/scopes.rb +17 -0
- data/app/models/comable/order/validations.rb +39 -0
- data/app/models/comable/order_item.rb +98 -0
- data/app/models/comable/order_item/csvable.rb +32 -0
- data/app/models/comable/page.rb +30 -0
- data/app/models/comable/payment.rb +87 -0
- data/app/models/comable/payment_method.rb +27 -0
- data/app/models/comable/product.rb +55 -0
- data/app/models/comable/product/csvable.rb +20 -0
- data/app/models/comable/shipment.rb +85 -0
- data/app/models/comable/shipment_method.rb +9 -0
- data/app/models/comable/stock.rb +71 -0
- data/app/models/comable/stock/csvable.rb +26 -0
- data/app/models/comable/store.rb +30 -0
- data/app/models/comable/theme.rb +25 -0
- data/app/models/comable/tracker.rb +17 -0
- data/app/models/comable/user.rb +130 -0
- data/app/models/concerns/comable/cart_owner.rb +94 -0
- data/app/models/concerns/comable/checkout.rb +85 -0
- data/app/models/concerns/comable/importable.rb +67 -0
- data/app/models/concerns/comable/liquidable.rb +12 -0
- data/app/models/concerns/comable/product/search.rb +41 -0
- data/app/models/concerns/comable/ransackable.rb +38 -0
- data/app/models/concerns/comable/role_owner.rb +15 -0
- data/app/models/concerns/comable/sku_choice.rb +19 -0
- data/app/models/concerns/comable/sku_item.rb +17 -0
- data/app/uploaders/image_uploader.rb +7 -0
- data/app/views/comable/order_mailer/complete.text.erb +42 -0
- data/config/initializers/comma.rb +8 -0
- data/config/locales/en.yml +424 -0
- data/config/locales/ja.yml +425 -0
- data/db/migrate/20131214194807_create_comable_products.rb +15 -0
- data/db/migrate/20140120032559_create_comable_users.rb +46 -0
- data/db/migrate/20140502060116_create_comable_stocks.rb +14 -0
- data/db/migrate/20140723175431_create_comable_orders.rb +20 -0
- data/db/migrate/20140723175810_create_comable_order_items.rb +19 -0
- data/db/migrate/20140817194104_create_comable_payment_methods.rb +13 -0
- data/db/migrate/20140921191416_create_comable_shipment_methods.rb +11 -0
- data/db/migrate/20140926063541_create_comable_stores.rb +11 -0
- data/db/migrate/20141024025526_create_comable_addresses.rb +17 -0
- data/db/migrate/20150111031228_create_comable_categories.rb +10 -0
- data/db/migrate/20150111031229_create_comable_products_categories.rb +8 -0
- data/db/migrate/20150112173706_create_comable_images.rb +9 -0
- data/db/migrate/20150423095210_create_comable_shipments.rb +13 -0
- data/db/migrate/20150511171940_create_comable_payments.rb +12 -0
- data/db/migrate/20150513185230_create_comable_trackers.rb +12 -0
- data/db/migrate/20150519080729_create_comable_pages.rb +17 -0
- data/db/migrate/20150612143226_create_comable_themes.rb +15 -0
- data/db/migrate/20150612143445_add_theme_id_to_comable_stores.rb +7 -0
- data/db/seeds.rb +5 -0
- data/db/seeds/comable/users.rb +51 -0
- data/lib/comable/core.rb +48 -0
- data/lib/comable/core/configuration.rb +22 -0
- data/lib/comable/core/engine.rb +50 -0
- data/lib/comable/deprecator.rb +26 -0
- data/lib/comable/payment_provider.rb +14 -0
- data/lib/comable/payment_provider/base.rb +42 -0
- data/lib/comable/payment_provider/general.rb +15 -0
- data/lib/comable/state_machine_patch.rb +32 -0
- data/lib/comma_extractor_extentions.rb +31 -0
- data/lib/generators/comable/install/install_generator.rb +133 -0
- data/lib/generators/comable/install/templates/config/initializers/comable.rb +31 -0
- data/lib/tasks/comable_tasks.rake +4 -0
- metadata +346 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
module Comable
|
2
|
+
class Payment < ActiveRecord::Base
|
3
|
+
include Comable::Ransackable
|
4
|
+
|
5
|
+
belongs_to :order, class_name: Comable::Order.name, inverse_of: :payment
|
6
|
+
belongs_to :payment_method, class_name: Comable::PaymentMethod.name
|
7
|
+
|
8
|
+
before_validation :copy_attributes_from_payment_method, unless: :order_completed?
|
9
|
+
|
10
|
+
validates :order, presence: true
|
11
|
+
validates :payment_method, presence: true
|
12
|
+
validates :fee, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
13
|
+
|
14
|
+
delegate :name, to: :payment_method
|
15
|
+
delegate :payment_provider, to: :payment_method
|
16
|
+
delegate :authorize!, :complete!, :cancel!, :resume!, to: :payment_provider, prefix: :provider
|
17
|
+
|
18
|
+
ransack_options ransackable_attributes: { except: [:order_id, :payment_method_id] }
|
19
|
+
|
20
|
+
# The #state attribute assigns the following values:
|
21
|
+
#
|
22
|
+
# pending when Order is not able to pay (default)
|
23
|
+
# ready when Order is able to pay
|
24
|
+
# completed when Order is already paid
|
25
|
+
# canceled when Order is canceled
|
26
|
+
# resumed when Order is resumed from the "canceled" state
|
27
|
+
state_machine initial: :pending do
|
28
|
+
state :pending
|
29
|
+
state :ready
|
30
|
+
state :completed
|
31
|
+
state :canceled
|
32
|
+
state :resumed
|
33
|
+
|
34
|
+
event :next_state do
|
35
|
+
transition :pending => :ready
|
36
|
+
transition :ready => :completed
|
37
|
+
end
|
38
|
+
|
39
|
+
event :cancel do
|
40
|
+
transition [:completed, :resumed] => :canceled
|
41
|
+
end
|
42
|
+
|
43
|
+
event :resume do
|
44
|
+
transition :canceled => :resumed
|
45
|
+
end
|
46
|
+
|
47
|
+
after_transition to: :ready, do: :next_state!
|
48
|
+
before_transition to: :ready, do: -> (s) { s.provider_authorize! }
|
49
|
+
before_transition to: :completed, do: -> (s) { s.complete! }
|
50
|
+
before_transition to: :canceled, do: -> (s) { s.provider_cancel! }
|
51
|
+
before_transition to: :canceled, do: -> (s) { s.provider_resume! }
|
52
|
+
end
|
53
|
+
|
54
|
+
class << self
|
55
|
+
def state_names
|
56
|
+
state_machine.states.keys
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def stated?(target_state)
|
61
|
+
target_state_index = self.class.state_names.index(target_state.to_sym)
|
62
|
+
current_state_index = self.class.state_names.index(state_name)
|
63
|
+
target_state_index < current_state_index
|
64
|
+
end
|
65
|
+
|
66
|
+
def completed?
|
67
|
+
completed_at?
|
68
|
+
end
|
69
|
+
|
70
|
+
def complete!
|
71
|
+
provider_complete!
|
72
|
+
touch :completed_at
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def order_completed?
|
78
|
+
order.completed?
|
79
|
+
end
|
80
|
+
|
81
|
+
def copy_attributes_from_payment_method
|
82
|
+
self.attributes = {
|
83
|
+
fee: payment_method.fee
|
84
|
+
}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Comable
|
2
|
+
class PaymentMethod < ActiveRecord::Base
|
3
|
+
validates :name, presence: true, length: { maximum: 255 }
|
4
|
+
validates :payment_provider_type, presence: true, length: { maximum: 255 }
|
5
|
+
validates :payment_provider_kind, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
6
|
+
validates :fee, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
7
|
+
validates :enable_price_from, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
|
8
|
+
validates :enable_price_to, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
|
9
|
+
|
10
|
+
def payment_provider
|
11
|
+
return unless Object.const_defined?(payment_provider_type)
|
12
|
+
Object.const_get(payment_provider_type)
|
13
|
+
end
|
14
|
+
|
15
|
+
def payment_provider_name
|
16
|
+
payment_provider.display_name
|
17
|
+
end
|
18
|
+
|
19
|
+
def payment_provider_kind_key
|
20
|
+
payment_provider.kind.keys.slice(payment_provider_kind)
|
21
|
+
end
|
22
|
+
|
23
|
+
def payment_provider_kind_name
|
24
|
+
payment_provider.kind.slice(payment_provider_kind_key).values.first
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Comable
|
2
|
+
class Product < ActiveRecord::Base
|
3
|
+
include Comable::SkuItem
|
4
|
+
include Comable::Ransackable
|
5
|
+
include Comable::Liquidable
|
6
|
+
include Comable::Product::Search
|
7
|
+
include Comable::Product::Csvable
|
8
|
+
|
9
|
+
has_many :stocks, class_name: Comable::Stock.name, dependent: :destroy
|
10
|
+
has_many :images, class_name: Comable::Image.name, dependent: :destroy
|
11
|
+
has_and_belongs_to_many :categories, class_name: Comable::Category.name, join_table: :comable_products_categories
|
12
|
+
|
13
|
+
accepts_nested_attributes_for :images, allow_destroy: true
|
14
|
+
|
15
|
+
validates :name, presence: true, length: { maximum: 255 }
|
16
|
+
validates :code, presence: true, length: { maximum: 255 }
|
17
|
+
validates :price, presence: true, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
|
18
|
+
validates :sku_h_item_name, length: { maximum: 255 }
|
19
|
+
validates :sku_v_item_name, length: { maximum: 255 }
|
20
|
+
|
21
|
+
liquid_methods :id, :code, :name, :price, :images, :image_url
|
22
|
+
|
23
|
+
ransack_options attribute_select: { associations: :stocks }
|
24
|
+
|
25
|
+
# Add conditions for the images association.
|
26
|
+
# Override method of the images association to support Rails 3.x.
|
27
|
+
def images
|
28
|
+
super.order(:id)
|
29
|
+
end
|
30
|
+
|
31
|
+
def image_url
|
32
|
+
image = images.first
|
33
|
+
return image.url if image
|
34
|
+
'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMTcxIiBoZWlnaHQ9IjE4MCIgdmlld0JveD0iMCAwIDE3MSAxODAiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxkZWZzLz48cmVjdCB3aWR0aD0iMTcxIiBoZWlnaHQ9IjE4MCIgZmlsbD0iI0VFRUVFRSIvPjxnPjx0ZXh0IHg9IjU4IiB5PSI5MCIgc3R5bGU9ImZpbGw6I0FBQUFBQTtmb250LXdlaWdodDpib2xkO2ZvbnQtZmFtaWx5OkFyaWFsLCBIZWx2ZXRpY2EsIE9wZW4gU2Fucywgc2Fucy1zZXJpZiwgbW9ub3NwYWNlO2ZvbnQtc2l6ZToxMHB0O2RvbWluYW50LWJhc2VsaW5lOmNlbnRyYWwiPjE3MXgxODA8L3RleHQ+PC9nPjwvc3ZnPg=='
|
35
|
+
end
|
36
|
+
|
37
|
+
def stocked?
|
38
|
+
stocks.stocked.exists?
|
39
|
+
end
|
40
|
+
|
41
|
+
def unstocked?
|
42
|
+
!stocked?
|
43
|
+
end
|
44
|
+
|
45
|
+
def category_path_names=(category_path_names, delimiter: Comable::Category::DEFAULT_PATH_NAME_DELIMITER)
|
46
|
+
self.categories = Comable::Category.find_by_path_names(category_path_names, delimiter: delimiter)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def create_stock
|
52
|
+
stocks.create(code: code) unless stocks.exists?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Comable
|
2
|
+
class Product < ActiveRecord::Base
|
3
|
+
module Csvable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
include Comable::Importable
|
7
|
+
|
8
|
+
included do
|
9
|
+
comma do
|
10
|
+
name
|
11
|
+
code
|
12
|
+
price
|
13
|
+
caption
|
14
|
+
sku_h_item_name
|
15
|
+
sku_v_item_name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Comable
|
2
|
+
class Shipment < ActiveRecord::Base
|
3
|
+
include Comable::Ransackable
|
4
|
+
|
5
|
+
belongs_to :order, class_name: Comable::Order.name, inverse_of: :shipment
|
6
|
+
belongs_to :shipment_method, class_name: Comable::ShipmentMethod.name
|
7
|
+
|
8
|
+
before_validation :copy_attributes_from_shipment_method, unless: :order_completed?
|
9
|
+
|
10
|
+
validates :order, presence: true
|
11
|
+
validates :shipment_method, presence: true
|
12
|
+
validates :fee, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
13
|
+
validates :tracking_number, length: { maximum: 255 }
|
14
|
+
|
15
|
+
delegate :name, to: :shipment_method
|
16
|
+
|
17
|
+
ransack_options ransackable_attributes: { except: [:order_id, :shipment_method_id] }
|
18
|
+
|
19
|
+
# The #state attribute assigns the following values:
|
20
|
+
#
|
21
|
+
# pending when Order is not able to ship (default)
|
22
|
+
# ready when Order is able to ship
|
23
|
+
# completed when Order is already shipped
|
24
|
+
# canceled when Order is canceled
|
25
|
+
# resumed when Order is resumed from the "canceled" state
|
26
|
+
state_machine initial: :pending do
|
27
|
+
state :pending
|
28
|
+
state :ready
|
29
|
+
state :completed
|
30
|
+
state :canceled
|
31
|
+
state :resumed
|
32
|
+
|
33
|
+
event :next_state do
|
34
|
+
transition :pending => :ready
|
35
|
+
transition :ready => :completed
|
36
|
+
end
|
37
|
+
|
38
|
+
event :ship do
|
39
|
+
transition :ready => :completed
|
40
|
+
end
|
41
|
+
|
42
|
+
event :cancel do
|
43
|
+
transition [:completed, :resumed] => :canceled
|
44
|
+
end
|
45
|
+
|
46
|
+
event :resume do
|
47
|
+
transition :canceled => :resumed
|
48
|
+
end
|
49
|
+
|
50
|
+
before_transition to: :completed, do: -> (s) { s.complete! }
|
51
|
+
end
|
52
|
+
|
53
|
+
class << self
|
54
|
+
def state_names
|
55
|
+
state_machine.states.keys
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def stated?(target_state)
|
60
|
+
target_state_index = self.class.state_names.index(target_state.to_sym)
|
61
|
+
current_state_index = self.class.state_names.index(state_name)
|
62
|
+
target_state_index < current_state_index
|
63
|
+
end
|
64
|
+
|
65
|
+
def completed?
|
66
|
+
completed_at?
|
67
|
+
end
|
68
|
+
|
69
|
+
def complete!
|
70
|
+
touch :completed_at
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def order_completed?
|
76
|
+
order.completed?
|
77
|
+
end
|
78
|
+
|
79
|
+
def copy_attributes_from_shipment_method
|
80
|
+
self.attributes = {
|
81
|
+
fee: shipment_method.fee
|
82
|
+
}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Comable
|
2
|
+
class ShipmentMethod < ActiveRecord::Base
|
3
|
+
validates :name, presence: true, length: { maximum: 255 }
|
4
|
+
validates :fee, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
5
|
+
validates :traking_url, length: { maximum: 255 }
|
6
|
+
|
7
|
+
scope :activated, -> { where(activated_flag: true) }
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Comable
|
2
|
+
#
|
3
|
+
# 在庫モデル。
|
4
|
+
# 商品に複数紐付き、品数やSKU(Stock Keeping Unit)情報を保持する。
|
5
|
+
#
|
6
|
+
class Stock < ActiveRecord::Base
|
7
|
+
include Comable::SkuItem
|
8
|
+
include Comable::SkuChoice
|
9
|
+
include Comable::Ransackable
|
10
|
+
include Comable::Liquidable
|
11
|
+
include Comable::Stock::Csvable
|
12
|
+
|
13
|
+
belongs_to :product, class_name: Comable::Product.name
|
14
|
+
|
15
|
+
#
|
16
|
+
# @!group Scope
|
17
|
+
#
|
18
|
+
|
19
|
+
# @!scope class
|
20
|
+
# 品切れでない在庫インスタンスを返す
|
21
|
+
scope :stocked, -> { where('quantity > ?', 0) }
|
22
|
+
|
23
|
+
# @!scope class
|
24
|
+
# 品切れの在庫インスタンスを返す
|
25
|
+
scope :unstocked, -> { where('quantity <= ?', 0) }
|
26
|
+
|
27
|
+
#
|
28
|
+
# @!endgroup
|
29
|
+
#
|
30
|
+
|
31
|
+
validates :product, presence: { message: Comable.t('admin.is_not_exists') }
|
32
|
+
validates :code, presence: true, length: { maximum: 255 }
|
33
|
+
validates :sku_h_choice_name, length: { maximum: 255 }
|
34
|
+
validates :sku_v_choice_name, length: { maximum: 255 }
|
35
|
+
# TODO: add conditions (by limitless flag, backoder flag and etc..)
|
36
|
+
validates :quantity, numericality: { greater_than_or_equal_to: 0 }
|
37
|
+
|
38
|
+
delegate :name, to: :product
|
39
|
+
delegate :price, to: :product
|
40
|
+
delegate :sku_h_item_name, to: :product
|
41
|
+
delegate :sku_v_item_name, to: :product
|
42
|
+
|
43
|
+
ransack_options attribute_select: { associations: :product }, ransackable_attributes: { except: :product_id }
|
44
|
+
|
45
|
+
# 在庫の有無を取得する
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# stock.quanaity = 1
|
49
|
+
# stock.stocked? #=> true
|
50
|
+
#
|
51
|
+
# @param quantity [Fixnum] 減算する在庫数を指定する
|
52
|
+
# @return [Boolean] 在庫があれば true を返す
|
53
|
+
# @see #unstocked?
|
54
|
+
def stocked?(quantity: 1)
|
55
|
+
(self.quantity - quantity) >= 0
|
56
|
+
end
|
57
|
+
|
58
|
+
# 在庫の有無を取得する
|
59
|
+
#
|
60
|
+
# @example
|
61
|
+
# stock.quanaity = 1
|
62
|
+
# stock.unstocked? #=> false
|
63
|
+
#
|
64
|
+
# @param quantity [Fixnum] 減算する在庫数を指定する
|
65
|
+
# @return [Boolean] {#stocked?} の逆。在庫がなければ true を返す
|
66
|
+
# @see #stocked?
|
67
|
+
def unstocked?(quantity: 1)
|
68
|
+
!stocked?(quantity: quantity)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Comable
|
2
|
+
class Stock < ActiveRecord::Base
|
3
|
+
module Csvable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
include Comable::Importable
|
7
|
+
|
8
|
+
included do
|
9
|
+
comma do
|
10
|
+
product_code
|
11
|
+
code
|
12
|
+
quantity
|
13
|
+
sku_h_choice_name
|
14
|
+
sku_v_choice_name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
delegate :code, to: :product, prefix: true, allow_nil: true
|
19
|
+
|
20
|
+
def product_code=(code)
|
21
|
+
return if product_code == code
|
22
|
+
self.product = Comable::Product.find_by(code: code)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Comable
|
2
|
+
class Store < ActiveRecord::Base
|
3
|
+
include Comable::Liquidable
|
4
|
+
|
5
|
+
belongs_to :theme, class_name: Comable::Theme.name
|
6
|
+
|
7
|
+
validates :name, length: { maximum: 255 }
|
8
|
+
validates :meta_keywords, length: { maximum: 255 }
|
9
|
+
validates :meta_description, length: { maximum: 255 }
|
10
|
+
validates :email, length: { maximum: 255 }
|
11
|
+
|
12
|
+
liquid_methods :name, :meta_keywords, :meta_description, :email
|
13
|
+
|
14
|
+
delegate :name, to: :theme, prefix: true, allow_nil: true
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def instance
|
18
|
+
first || new(name: default_name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_name
|
22
|
+
Comable.t('default_store_name')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def can_send_mail?
|
27
|
+
email.present?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Comable
|
2
|
+
class Theme < ActiveRecord::Base
|
3
|
+
has_one :store, class_name: Comable::Store.name
|
4
|
+
|
5
|
+
validates :name, uniqueness: { scope: :version }
|
6
|
+
validates :name, presence: true, length: { maximum: 255 }
|
7
|
+
validates :version, presence: true, length: { maximum: 255 }
|
8
|
+
validates :display, length: { maximum: 255 }
|
9
|
+
validates :description, length: { maximum: 255 }
|
10
|
+
validates :homepage, length: { maximum: 255 }
|
11
|
+
validates :author, length: { maximum: 255 }
|
12
|
+
|
13
|
+
def default_version
|
14
|
+
'0.1.0'
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_param
|
18
|
+
name
|
19
|
+
end
|
20
|
+
|
21
|
+
def display_name
|
22
|
+
display.presence || name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|