biovision-vote 0.1.2.170925 → 0.2.180610
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/app/assets/images/biovision/vote/icons/downvote-active.svg +1 -3
- data/app/assets/images/biovision/vote/icons/downvote-error.svg +1 -3
- data/app/assets/images/biovision/vote/icons/downvote-switch.svg +1 -3
- data/app/assets/images/biovision/vote/icons/downvote.svg +1 -3
- data/app/assets/images/biovision/vote/icons/upvote-active.svg +1 -3
- data/app/assets/images/biovision/vote/icons/upvote-error.svg +1 -3
- data/app/assets/images/biovision/vote/icons/upvote-switch.svg +1 -3
- data/app/assets/images/biovision/vote/icons/upvote.svg +1 -3
- data/app/assets/javascripts/biovision/vote/biovision-vote.js +56 -4
- data/app/controllers/votes_controller.rb +3 -3
- data/app/models/concerns/votable_item.rb +11 -11
- data/app/models/vote.rb +25 -6
- data/app/views/admin/index/dashboard/_biovision_vote.html.erb +10 -0
- data/app/views/admin/votes/_nav_item.html.erb +2 -6
- data/app/views/admin/votes/entity/_in_list.html.erb +4 -9
- data/app/views/votes/_vote_block.html.erb +5 -2
- data/app/views/votes/result.jbuilder +1 -1
- data/config/locales/votes-en.yml +37 -0
- data/config/locales/votes-ru.yml +11 -5
- data/config/routes.rb +7 -3
- data/db/migrate/20170330000001_create_votes.rb +19 -10
- data/db/migrate/20180610110015_add_slug_to_votes.rb +15 -0
- data/lib/biovision/vote/engine.rb +1 -1
- data/lib/biovision/vote/version.rb +1 -1
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: adda0f4c749b69d036ee7ed68eeb0bf5c7b239b0bcf1e319a0b41047159fa528
|
4
|
+
data.tar.gz: 70afc612c239040da36ab2d3c4e576749bd2ae5301373ece07dd80029f97a118
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc1b959e92bb5d0bfb80d52fc8253bb3b5c049348cdb38bb2aa55a8aa5622a7b112dc464169dc273a0e3880a6eb93ecaf3255ba5d2bc87d1c53cfb02c42dcd94
|
7
|
+
data.tar.gz: 9d72d310271a1939606abfbe25e8ae66ad06932caf9293002a4a08a3ad43da0438cf0ad937c546db393076211cedc9d4817f2480ec075bc6385d8d28ff4da94b
|
@@ -1,3 +1 @@
|
|
1
|
-
<svg version="1.1"
|
2
|
-
<polyline points="9 2, 9 12, 4 12, 11 21, 13 21, 20 12, 15 12, 15 2, 9 2" fill="#822" stroke="#844" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
3
|
-
</svg>
|
1
|
+
<svg version="1.1" viewBox="0 0 24 24" width="24" height="24" xmlns="http://www.w3.org/2000/svg"><polyline points="9 2, 9 12, 4 12, 11 21, 13 21, 20 12, 15 12, 15 2, 9 2" fill="#822" stroke="#844" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
@@ -1,3 +1 @@
|
|
1
|
-
<svg version="1.1"
|
2
|
-
<polyline points="9 2, 9 12, 4 12, 11 21, 13 21, 20 12, 15 12, 15 2, 9 2" fill="#888" stroke="#444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
3
|
-
</svg>
|
1
|
+
<svg version="1.1" viewBox="0 0 24 24" width="24" height="24" xmlns="http://www.w3.org/2000/svg"><polyline points="9 2, 9 12, 4 12, 11 21, 13 21, 20 12, 15 12, 15 2, 9 2" fill="#888" stroke="#444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
@@ -1,3 +1 @@
|
|
1
|
-
<svg version="1.1"
|
2
|
-
<polyline points="9 2, 9 12, 4 12, 11 21, 13 21, 20 12, 15 12, 15 2, 9 2" fill="#ff4" stroke="#884" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
3
|
-
</svg>
|
1
|
+
<svg version="1.1" viewBox="0 0 24 24" width="24" height="24" xmlns="http://www.w3.org/2000/svg"><polyline points="9 2, 9 12, 4 12, 11 21, 13 21, 20 12, 15 12, 15 2, 9 2" fill="#ff4" stroke="#884" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
@@ -1,3 +1 @@
|
|
1
|
-
<svg version="1.1"
|
2
|
-
<polyline points="9 2, 9 12, 4 12, 11 21, 13 21, 20 12, 15 12, 15 2, 9 2" fill="none" stroke="#844" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
3
|
-
</svg>
|
1
|
+
<svg version="1.1" viewBox="0 0 24 24" width="24" height="24" xmlns="http://www.w3.org/2000/svg"><polyline points="9 2, 9 12, 4 12, 11 21, 13 21, 20 12, 15 12, 15 2, 9 2" fill="none" stroke="#844" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
@@ -1,3 +1 @@
|
|
1
|
-
<svg version="1.1"
|
2
|
-
<polyline points="9 21, 9 11, 4 11, 11 2, 13 2, 20 11, 15 11, 15 21, 9 21" fill="#282" stroke="#484" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
3
|
-
</svg>
|
1
|
+
<svg version="1.1" viewBox="0 0 24 24" width="24" height="24" xmlns="http://www.w3.org/2000/svg"><polyline points="9 21, 9 11, 4 11, 11 2, 13 2, 20 11, 15 11, 15 21, 9 21" fill="#282" stroke="#484" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
@@ -1,3 +1 @@
|
|
1
|
-
<svg version="1.1"
|
2
|
-
<polyline points="9 21, 9 11, 4 11, 11 2, 13 2, 20 11, 15 11, 15 21, 9 21" fill="#888" stroke="#444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
3
|
-
</svg>
|
1
|
+
<svg version="1.1" viewBox="0 0 24 24" width="24" height="24" xmlns="http://www.w3.org/2000/svg"><polyline points="9 21, 9 11, 4 11, 11 2, 13 2, 20 11, 15 11, 15 21, 9 21" fill="#888" stroke="#444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
@@ -1,3 +1 @@
|
|
1
|
-
<svg version="1.1"
|
2
|
-
<polyline points="9 21, 9 11, 4 11, 11 2, 13 2, 20 11, 15 11, 15 21, 9 21" fill="#ff4" stroke="#884" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
3
|
-
</svg>
|
1
|
+
<svg version="1.1" viewBox="0 0 24 24" width="24" height="24" xmlns="http://www.w3.org/2000/svg"><polyline points="9 21, 9 11, 4 11, 11 2, 13 2, 20 11, 15 11, 15 21, 9 21" fill="#ff4" stroke="#884" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
@@ -1,3 +1 @@
|
|
1
|
-
<svg version="1.1"
|
2
|
-
<polyline points="9 21, 9 11, 4 11, 11 2, 13 2, 20 11, 15 11, 15 21, 9 21" fill="none" stroke="#484" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
3
|
-
</svg>
|
1
|
+
<svg version="1.1" viewBox="0 0 24 24" width="24" height="24" xmlns="http://www.w3.org/2000/svg"><polyline points="9 21, 9 11, 4 11, 11 2, 13 2, 20 11, 15 11, 15 21, 9 21" fill="none" stroke="#484" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
@@ -16,9 +16,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
16
16
|
const result = JSON.parse(this.responseText);
|
17
17
|
|
18
18
|
$button.classList.remove('switch');
|
19
|
-
if (result.hasOwnProperty('
|
20
|
-
const vote_type = result['
|
21
|
-
const vote_result = result['
|
19
|
+
if (result.hasOwnProperty('meta')) {
|
20
|
+
const vote_type = result['meta']['vote_type'];
|
21
|
+
const vote_result = result['meta']['vote_result'];
|
22
22
|
|
23
23
|
$container.classList.remove('voted-none');
|
24
24
|
$container.classList.add('voted-' + vote_type);
|
@@ -26,7 +26,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
26
26
|
}
|
27
27
|
};
|
28
28
|
|
29
|
-
const on_failure = function(result) {
|
29
|
+
const on_failure = function (result) {
|
30
30
|
$button.classList.remove('switch');
|
31
31
|
$button.classList.add('error');
|
32
32
|
handle_ajax_failure(result);
|
@@ -42,4 +42,56 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
42
42
|
$container.classList.remove('active');
|
43
43
|
});
|
44
44
|
});
|
45
|
+
|
46
|
+
document.querySelectorAll('[data-vote]').forEach(function (button) {
|
47
|
+
const container = button.closest('[data-vote-url]');
|
48
|
+
if (container) {
|
49
|
+
if (container.classList.contains('vote-active')) {
|
50
|
+
const url = container.getAttribute('data-vote-url');
|
51
|
+
|
52
|
+
button.addEventListener('click', function () {
|
53
|
+
const delta = this.getAttribute('data-vote') === 'up' ? 1 : -1;
|
54
|
+
const pressedButton = this;
|
55
|
+
|
56
|
+
/**
|
57
|
+
* Во время голосования состояние переключается
|
58
|
+
* на vote-inactive, поэтому проверяем ещё раз
|
59
|
+
*/
|
60
|
+
if (container.classList.contains('vote-active')) {
|
61
|
+
const data = {
|
62
|
+
vote: {
|
63
|
+
votable_id: container.getAttribute('data-votable-id'),
|
64
|
+
votable_type: container.getAttribute('data-votable-type'),
|
65
|
+
delta: delta,
|
66
|
+
}
|
67
|
+
};
|
68
|
+
|
69
|
+
const request = Biovision.jsonAjaxRequest('POST', url, function () {
|
70
|
+
if (this.responseText) {
|
71
|
+
const response = JSON.parse(this.responseText);
|
72
|
+
|
73
|
+
if (response.hasOwnProperty('meta')) {
|
74
|
+
if (delta > 0) {
|
75
|
+
pressedButton.innerHTML = response.meta['upvote_count'];
|
76
|
+
} else {
|
77
|
+
pressedButton.innerHTML = response.meta['downvote_count'];
|
78
|
+
}
|
79
|
+
container.classList.remove('voted-none');
|
80
|
+
container.classList.add('voted-' + response.meta['vote_type']);
|
81
|
+
}
|
82
|
+
} else {
|
83
|
+
container.classList.remove('vote-inactive');
|
84
|
+
container.classList.add('vote-active');
|
85
|
+
}
|
86
|
+
});
|
87
|
+
|
88
|
+
container.classList.remove('vote-active');
|
89
|
+
container.classList.add('vote-inactive');
|
90
|
+
|
91
|
+
request.send(JSON.stringify(data));
|
92
|
+
}
|
93
|
+
});
|
94
|
+
}
|
95
|
+
}
|
96
|
+
});
|
45
97
|
});
|
@@ -4,10 +4,10 @@ class VotesController < ApplicationController
|
|
4
4
|
# post /votes
|
5
5
|
def create
|
6
6
|
@entity = Vote.new(creation_parameters)
|
7
|
-
if @entity.votable.
|
7
|
+
if @entity.votable.vote_applicable?(@entity)
|
8
8
|
process_vote
|
9
9
|
else
|
10
|
-
render :result, status: :
|
10
|
+
render :result, status: :unprocessable_entity
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -32,7 +32,7 @@ class VotesController < ApplicationController
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def process_vote
|
35
|
-
if Vote.voted?(
|
35
|
+
if Vote.voted?(@entity.current_slug, @entity.votable)
|
36
36
|
render :result, status: :conflict
|
37
37
|
else
|
38
38
|
count_vote
|
@@ -5,26 +5,26 @@ module VotableItem
|
|
5
5
|
has_many :votes, as: :votable, dependent: :destroy
|
6
6
|
end
|
7
7
|
|
8
|
-
# @param [
|
9
|
-
def
|
10
|
-
|
11
|
-
!Vote.voted?(
|
8
|
+
# @param [Vote|String] vote_or_slug
|
9
|
+
def vote_applicable?(vote_or_slug)
|
10
|
+
slug = vote_or_slug.is_a?(String) ? vote_or_slug : vote_or_slug.slug
|
11
|
+
!Vote.voted?(slug, self)
|
12
12
|
end
|
13
13
|
|
14
|
-
# @param [
|
15
|
-
def vote_data(
|
14
|
+
# @param [String|Vote] vote_or_slug
|
15
|
+
def vote_data(vote_or_slug)
|
16
16
|
{
|
17
17
|
upvote_count: upvote_count,
|
18
18
|
downvote_count: downvote_count,
|
19
19
|
vote_result: vote_result,
|
20
|
-
vote_type: voted(
|
20
|
+
vote_type: voted(vote_or_slug)
|
21
21
|
}
|
22
22
|
end
|
23
23
|
|
24
|
-
# @param [
|
25
|
-
def voted(
|
26
|
-
vote = votes.find_by(
|
27
|
-
return :none if vote.nil?
|
24
|
+
# @param [String|Vote] vote_or_slug
|
25
|
+
def voted(vote_or_slug)
|
26
|
+
vote = vote_or_slug.is_a?(String) ? votes.find_by(slug: vote_or_slug) : vote_or_slug
|
27
|
+
return :none if vote&.id.nil?
|
28
28
|
vote.upvote? ? :upvote : :downvote
|
29
29
|
end
|
30
30
|
end
|
data/app/models/vote.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
class Vote < ApplicationRecord
|
2
2
|
include HasOwner
|
3
3
|
|
4
|
-
PER_PAGE = 20
|
5
|
-
|
6
4
|
METRIC_VOTE_HIT = 'votes.any.hit'
|
7
5
|
METRIC_UPVOTE_HIT = 'votes.upvote.hit'
|
8
6
|
METRIC_DOWNVOTE_HIT = 'votes.downvote.hit'
|
@@ -12,22 +10,35 @@ class Vote < ApplicationRecord
|
|
12
10
|
belongs_to :votable, polymorphic: true
|
13
11
|
|
14
12
|
before_validation { self.delta = (delta.to_i > 0 ? 1 : -1) }
|
15
|
-
|
13
|
+
before_validation :generate_slug
|
14
|
+
validates_uniqueness_of :votable_id, scope: [:slug, :votable_type]
|
16
15
|
|
17
16
|
after_create :add_vote_result
|
18
17
|
after_destroy :discard_vote_result
|
19
18
|
|
20
19
|
scope :recent, -> { order('id desc') }
|
20
|
+
scope :list_for_administration, -> { recent }
|
21
21
|
|
22
22
|
# @param [Integer] page
|
23
23
|
def self.page_for_administration(page = 1)
|
24
|
-
|
24
|
+
list_for_administration.page(page)
|
25
25
|
end
|
26
26
|
|
27
27
|
# @param [User] user
|
28
|
+
# @param [String] ip
|
29
|
+
# @param [Integer] agent_id
|
30
|
+
def self.slug_string(user, ip, agent_id)
|
31
|
+
if user.nil?
|
32
|
+
"#{ip}:#{agent_id}"
|
33
|
+
else
|
34
|
+
user.id.to_s
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param [String] slug
|
28
39
|
# @param [ApplicationRecord] votable
|
29
|
-
def self.voted?(
|
30
|
-
exists?(
|
40
|
+
def self.voted?(slug, votable)
|
41
|
+
exists?(slug: slug, votable: votable)
|
31
42
|
end
|
32
43
|
|
33
44
|
# @param [User] user
|
@@ -56,8 +67,16 @@ class Vote < ApplicationRecord
|
|
56
67
|
owned_by?(user) || UserPrivilege.user_has_privilege?(:user, :moderator)
|
57
68
|
end
|
58
69
|
|
70
|
+
def current_slug
|
71
|
+
self.class.slug_string(user, ip, agent_id)
|
72
|
+
end
|
73
|
+
|
59
74
|
private
|
60
75
|
|
76
|
+
def generate_slug
|
77
|
+
self.slug = current_slug
|
78
|
+
end
|
79
|
+
|
61
80
|
def add_vote_result
|
62
81
|
votable.vote_result = votable.vote_result + delta
|
63
82
|
votable.upvote_count = votable.upvote_count + 1 if upvote?
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<% if current_user_has_privilege?(:moderator) %>
|
2
|
+
<nav>
|
3
|
+
<div class="heading" id="biovision-vote-nav-heading">
|
4
|
+
<%= t('.heading') %>
|
5
|
+
</div>
|
6
|
+
<ul aria-labelledby="biovision-vote-nav-heading">
|
7
|
+
<li><%= render 'admin/votes/nav_item' %></li>
|
8
|
+
</ul>
|
9
|
+
</nav>
|
10
|
+
<% end %>
|
@@ -2,13 +2,8 @@
|
|
2
2
|
<%= vote_image(entity) %>
|
3
3
|
</div>
|
4
4
|
<div class="data">
|
5
|
-
<div>
|
6
|
-
|
7
|
-
|
8
|
-
<div class="info">
|
9
|
-
<%= admin_user_link(entity.user) %>
|
10
|
-
</div>
|
11
|
-
<div class="secondary info">
|
12
|
-
<%= time_tag(entity.created_at) %>
|
13
|
-
</div>
|
5
|
+
<div><%= biovision_votable_link(entity.votable) %></div>
|
6
|
+
<div class="info"><%= admin_user_link(entity.user) %></div>
|
7
|
+
<div class="secondary info"><%= entity.slug %></div>
|
8
|
+
<div class="secondary info"><%= time_tag(entity.created_at) %></div>
|
14
9
|
</div>
|
@@ -1,5 +1,8 @@
|
|
1
|
-
<%
|
2
|
-
|
1
|
+
<%
|
2
|
+
slug = Vote.slug_string(current_user, request.env['HTTP_X_REAL_IP'] || request.remote_ip, agent.id)
|
3
|
+
block_class = votable.vote_applicable?(slug) ? 'active' : ''
|
4
|
+
%>
|
5
|
+
<div class="vote-block <%= block_class %> voted-<%= votable.voted(slug) %>" data-id="<%= votable.id %>">
|
3
6
|
<div class="vote upvote"></div>
|
4
7
|
<div class="result"><%= votable.vote_result %></div>
|
5
8
|
<div class="vote downvote"></div>
|
@@ -1 +1 @@
|
|
1
|
-
json.
|
1
|
+
json.meta @entity.votable.vote_data(@entity)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
en:
|
2
|
+
upvote_count:
|
3
|
+
zero: "no upvotes"
|
4
|
+
one: "%{count} upvote"
|
5
|
+
few: "%{count} upvotes"
|
6
|
+
many: "%{count} upvotes"
|
7
|
+
other: "%{count} upvotes"
|
8
|
+
downvote_count:
|
9
|
+
zero: "no downvotes"
|
10
|
+
one: "%{count} downvote"
|
11
|
+
few: "%{count} downvotes"
|
12
|
+
many: "%{count} downvotes"
|
13
|
+
other: "%{count} downvotes"
|
14
|
+
activerecord:
|
15
|
+
models:
|
16
|
+
vote: "Vote"
|
17
|
+
attributes:
|
18
|
+
vote:
|
19
|
+
agent: "User agent"
|
20
|
+
delta: "Delta"
|
21
|
+
ip: "IP address"
|
22
|
+
slug: "Slug"
|
23
|
+
user: "User"
|
24
|
+
votable: "Votable entity"
|
25
|
+
votable_id: "Votable entity"
|
26
|
+
admin:
|
27
|
+
votes:
|
28
|
+
nav_item:
|
29
|
+
description: "Manage user votes"
|
30
|
+
text: "User votes"
|
31
|
+
index:
|
32
|
+
heading: "User votes"
|
33
|
+
title: "User votes, page %{page}"
|
34
|
+
index:
|
35
|
+
dashboard:
|
36
|
+
biovision_vote:
|
37
|
+
heading: "User votes"
|
data/config/locales/votes-ru.yml
CHANGED
@@ -16,16 +16,22 @@ ru:
|
|
16
16
|
vote: "Голос"
|
17
17
|
attributes:
|
18
18
|
vote:
|
19
|
-
user: "Пользователь"
|
20
|
-
votable: "Объект голосования"
|
21
19
|
agent: "Агент пользователя"
|
22
|
-
ip: "IP-адрес"
|
23
20
|
delta: "Изменение"
|
21
|
+
ip: "IP-адрес"
|
22
|
+
slug: "Идентификатор"
|
23
|
+
user: "Пользователь"
|
24
|
+
votable: "Объект голосования"
|
25
|
+
votable_id: "Объект голосования"
|
24
26
|
admin:
|
25
27
|
votes:
|
26
28
|
nav_item:
|
27
|
-
text: "Голоса пользователей"
|
28
29
|
description: "Просмотр голосов пользователей"
|
30
|
+
text: "Голоса пользователей"
|
29
31
|
index:
|
30
|
-
title: "Голоса, страница %{page}"
|
31
32
|
heading: "Голоса пользователей"
|
33
|
+
title: "Голоса, страница %{page}"
|
34
|
+
index:
|
35
|
+
dashboard:
|
36
|
+
biovision_vote:
|
37
|
+
heading: "Голоса пользователей"
|
data/config/routes.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
Rails.application.routes.draw do
|
2
|
-
resources :votes, only: [:
|
2
|
+
resources :votes, only: [:destroy], defaults: { format: :json }
|
3
3
|
|
4
|
-
|
5
|
-
resources :votes, only: [:
|
4
|
+
scope '(:locale)', constraints: { locale: /ru|en/ } do
|
5
|
+
resources :votes, only: [:create], defaults: { format: :json }
|
6
|
+
|
7
|
+
namespace :admin do
|
8
|
+
resources :votes, only: [:index]
|
9
|
+
end
|
6
10
|
end
|
7
11
|
end
|
@@ -1,13 +1,22 @@
|
|
1
|
-
class CreateVotes < ActiveRecord::Migration[5.
|
2
|
-
def
|
3
|
-
|
4
|
-
t
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
class CreateVotes < ActiveRecord::Migration[5.1]
|
2
|
+
def up
|
3
|
+
unless Vote.table_exists?
|
4
|
+
create_table :votes do |t|
|
5
|
+
t.timestamps
|
6
|
+
t.references :user, foreign_key: true, on_update: :cascade, on_delete: :cascade
|
7
|
+
t.references :agent, foreign_key: true, on_update: :cascade, on_delete: :nullify
|
8
|
+
t.inet :ip
|
9
|
+
t.integer :delta, limit: 2, default: 0, null: false
|
10
|
+
t.integer :votable_id, null: false
|
11
|
+
t.string :votable_type, null: false
|
12
|
+
t.string :slug, index: true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def down
|
18
|
+
if Vote.table_exists?
|
19
|
+
drop_table :votes
|
11
20
|
end
|
12
21
|
end
|
13
22
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class AddSlugToVotes < ActiveRecord::Migration[5.2]
|
2
|
+
def up
|
3
|
+
unless column_exists?(:votes, :slug)
|
4
|
+
add_column :votes, :slug, :string, index: true
|
5
|
+
|
6
|
+
Vote.order('id asc').each do |vote|
|
7
|
+
vote.update! slug: vote.current_slug
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def down
|
13
|
+
# No need to rollback
|
14
|
+
end
|
15
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: biovision-vote
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.180610
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maxim Khan-Magomedov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: factory_bot_rails
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - ">="
|
@@ -154,15 +154,18 @@ files:
|
|
154
154
|
- app/models/biovision/vote/application_record.rb
|
155
155
|
- app/models/concerns/votable_item.rb
|
156
156
|
- app/models/vote.rb
|
157
|
+
- app/views/admin/index/dashboard/_biovision_vote.html.erb
|
157
158
|
- app/views/admin/votes/_nav_item.html.erb
|
158
159
|
- app/views/admin/votes/entity/_in_list.html.erb
|
159
160
|
- app/views/admin/votes/index.html.erb
|
160
161
|
- app/views/layouts/biovision/vote/application.html.erb
|
161
162
|
- app/views/votes/_vote_block.html.erb
|
162
163
|
- app/views/votes/result.jbuilder
|
164
|
+
- config/locales/votes-en.yml
|
163
165
|
- config/locales/votes-ru.yml
|
164
166
|
- config/routes.rb
|
165
167
|
- db/migrate/20170330000001_create_votes.rb
|
168
|
+
- db/migrate/20180610110015_add_slug_to_votes.rb
|
166
169
|
- lib/biovision/vote.rb
|
167
170
|
- lib/biovision/vote/engine.rb
|
168
171
|
- lib/biovision/vote/version.rb
|
@@ -187,7 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
187
190
|
version: '0'
|
188
191
|
requirements: []
|
189
192
|
rubyforge_project:
|
190
|
-
rubygems_version: 2.6
|
193
|
+
rubygems_version: 2.7.6
|
191
194
|
signing_key:
|
192
195
|
specification_version: 4
|
193
196
|
summary: Voting functionality for biovision-based applications
|