antispam 0.2.0 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +20 -20
- data/README.md +129 -128
- data/Rakefile +18 -18
- data/app/assets/config/antispam_manifest.js +1 -1
- data/app/assets/stylesheets/antispam/application.css +15 -15
- data/app/assets/stylesheets/antispam/blocks.css +4 -4
- data/app/assets/stylesheets/antispam/challenges.css +4 -4
- data/app/assets/stylesheets/antispam/clears.css +4 -4
- data/app/assets/stylesheets/scaffold.css +80 -80
- data/app/controllers/antispam/application_controller.rb +11 -11
- data/app/controllers/antispam/blocks_controller.rb +28 -28
- data/app/controllers/antispam/challenges_controller.rb +50 -50
- data/app/controllers/antispam/clears_controller.rb +28 -28
- data/app/controllers/antispam/validate_controller.rb +12 -12
- data/app/helpers/antispam/application_helper.rb +4 -4
- data/app/helpers/antispam/blocks_helper.rb +4 -4
- data/app/helpers/antispam/challenges_helper.rb +4 -4
- data/app/helpers/antispam/clears_helper.rb +4 -4
- data/app/jobs/antispam/application_job.rb +4 -4
- data/app/mailers/antispam/application_mailer.rb +6 -6
- data/app/models/antispam/application_record.rb +5 -5
- data/app/models/antispam/block.rb +4 -4
- data/app/models/antispam/challenge.rb +26 -26
- data/app/models/antispam/clear.rb +4 -4
- data/app/models/antispam/ip.rb +11 -6
- data/app/views/antispam/blocks/index.html.erb +38 -38
- data/app/views/antispam/blocks/show.html.erb +24 -24
- data/app/views/antispam/challenges/_form.html.erb +32 -32
- data/app/views/antispam/challenges/edit.html.erb +6 -6
- data/app/views/antispam/challenges/index.html.erb +31 -31
- data/app/views/antispam/challenges/new.html.erb +5 -5
- data/app/views/antispam/challenges/show.html.erb +19 -19
- data/app/views/antispam/clears/index.html.erb +32 -32
- data/app/views/antispam/clears/show.html.erb +29 -29
- data/app/views/antispam/validate/index.html.erb +16 -14
- data/app/views/layouts/antispam/application.html.erb +25 -15
- data/config/routes.rb +7 -7
- data/db/migrate/20210130213708_create_antispam_ips.rb +12 -12
- data/db/migrate/20210130214835_create_antispam_challenges.rb +11 -11
- data/db/migrate/20210130234107_create_antispam_blocks.rb +12 -12
- data/db/migrate/20210130235537_create_antispam_clears.rb +13 -13
- data/db/migrate/20210131165122_add_threat_to_antispam_blocks.rb +5 -5
- data/lib/antispam/blacklists/httpbl.rb +49 -49
- data/lib/antispam/checker.rb +30 -30
- data/lib/antispam/engine.rb +5 -5
- data/lib/antispam/results.rb +18 -18
- data/lib/antispam/spamcheckers/defendium.rb +29 -29
- data/lib/antispam/tools.rb +59 -59
- data/lib/antispam/version.rb +3 -3
- data/lib/antispam.rb +21 -17
- data/lib/tasks/antispam_tasks.rake +4 -4
- metadata +6 -6
@@ -1,28 +1,28 @@
|
|
1
|
-
require_dependency "antispam/application_controller"
|
2
|
-
|
3
|
-
module Antispam
|
4
|
-
class BlocksController < ApplicationController
|
5
|
-
before_action :must_be_admin
|
6
|
-
before_action :set_block, only: [:show]
|
7
|
-
|
8
|
-
# GET /blocks
|
9
|
-
def index
|
10
|
-
@blocks = Block.all
|
11
|
-
end
|
12
|
-
|
13
|
-
# GET /blocks/1
|
14
|
-
def show
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
# Use callbacks to share common setup or constraints between actions.
|
19
|
-
def set_block
|
20
|
-
@block = Block.find(params[:id])
|
21
|
-
end
|
22
|
-
|
23
|
-
# Only allow a list of trusted parameters through.
|
24
|
-
def block_params
|
25
|
-
params.require(:block).permit(:ip, :provider, :controllername, :actionname)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
1
|
+
require_dependency "antispam/application_controller"
|
2
|
+
|
3
|
+
module Antispam
|
4
|
+
class BlocksController < ApplicationController
|
5
|
+
before_action :must_be_admin
|
6
|
+
before_action :set_block, only: [:show]
|
7
|
+
|
8
|
+
# GET /blocks
|
9
|
+
def index
|
10
|
+
@blocks = Block.all
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /blocks/1
|
14
|
+
def show
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
# Use callbacks to share common setup or constraints between actions.
|
19
|
+
def set_block
|
20
|
+
@block = Block.find(params[:id])
|
21
|
+
end
|
22
|
+
|
23
|
+
# Only allow a list of trusted parameters through.
|
24
|
+
def block_params
|
25
|
+
params.require(:block).permit(:ip, :provider, :controllername, :actionname)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,50 +1,50 @@
|
|
1
|
-
require_dependency "antispam/application_controller"
|
2
|
-
|
3
|
-
module Antispam
|
4
|
-
class ChallengesController < ApplicationController
|
5
|
-
before_action :set_challenge, only: [:show, :edit, :update, :destroy]
|
6
|
-
|
7
|
-
# GET /challenges/1
|
8
|
-
def show
|
9
|
-
respond_to do |format|
|
10
|
-
format.jpeg do
|
11
|
-
image = @challenge.get_image
|
12
|
-
render content_type: 'image/jpeg', plain: image.jpegsave_buffer
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
# GET /challenges/new
|
18
|
-
def new
|
19
|
-
# use in the future for changing code
|
20
|
-
head :ok
|
21
|
-
end
|
22
|
-
|
23
|
-
# PATCH/PUT /challenges/1
|
24
|
-
def update
|
25
|
-
if @challenge.validate?(params[:challenge][:answer])
|
26
|
-
a = Antispam::Ip.find_or_create_by(address: request.remote_ip, provider: 'httpbl')
|
27
|
-
before = a.threat
|
28
|
-
a.threat = [(a.threat || 0) - 25, 0].max
|
29
|
-
c = Clear.create(ip: request.remote_ip, answer: params[:challenge][:answer], result: 'Passed', threat_before: before, threat_after: a.threat)
|
30
|
-
a.expires_at = 1.hour.from_now
|
31
|
-
a.save
|
32
|
-
redirect_to '/'
|
33
|
-
else
|
34
|
-
c = Clear.create(ip: request.remote_ip, answer: params[:challenge][:answer], result: 'Failed')
|
35
|
-
redirect_to '/antispam/validate', notice: 'Invalid answer.'
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
# Use callbacks to share common setup or constraints between actions.
|
41
|
-
def set_challenge
|
42
|
-
@challenge = Challenge.find(params[:id])
|
43
|
-
end
|
44
|
-
|
45
|
-
# Only allow a list of trusted parameters through.
|
46
|
-
def challenge_params
|
47
|
-
params.require(:challenge).permit(:answer, :code)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
1
|
+
require_dependency "antispam/application_controller"
|
2
|
+
|
3
|
+
module Antispam
|
4
|
+
class ChallengesController < ApplicationController
|
5
|
+
before_action :set_challenge, only: [:show, :edit, :update, :destroy]
|
6
|
+
|
7
|
+
# GET /challenges/1
|
8
|
+
def show
|
9
|
+
respond_to do |format|
|
10
|
+
format.jpeg do
|
11
|
+
image = @challenge.get_image
|
12
|
+
render content_type: 'image/jpeg', plain: image.jpegsave_buffer
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# GET /challenges/new
|
18
|
+
def new
|
19
|
+
# use in the future for changing code
|
20
|
+
head :ok
|
21
|
+
end
|
22
|
+
|
23
|
+
# PATCH/PUT /challenges/1
|
24
|
+
def update
|
25
|
+
if @challenge.validate?(params[:challenge][:answer])
|
26
|
+
a = Antispam::Ip.find_or_create_by(address: request.remote_ip, provider: 'httpbl')
|
27
|
+
before = a.threat
|
28
|
+
a.threat = [(a.threat || 0) - 25, 0].max
|
29
|
+
c = Clear.create(ip: request.remote_ip, answer: params[:challenge][:answer], result: 'Passed', threat_before: before, threat_after: a.threat)
|
30
|
+
a.expires_at = 1.hour.from_now
|
31
|
+
a.save
|
32
|
+
redirect_to '/'
|
33
|
+
else
|
34
|
+
c = Clear.create(ip: request.remote_ip, answer: params[:challenge][:answer], result: 'Failed')
|
35
|
+
redirect_to '/antispam/validate', notice: 'Invalid answer.'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
# Use callbacks to share common setup or constraints between actions.
|
41
|
+
def set_challenge
|
42
|
+
@challenge = Challenge.find(params[:id])
|
43
|
+
end
|
44
|
+
|
45
|
+
# Only allow a list of trusted parameters through.
|
46
|
+
def challenge_params
|
47
|
+
params.require(:challenge).permit(:answer, :code)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -1,28 +1,28 @@
|
|
1
|
-
require_dependency "antispam/application_controller"
|
2
|
-
|
3
|
-
module Antispam
|
4
|
-
class ClearsController < ApplicationController
|
5
|
-
before_action :must_be_admin
|
6
|
-
before_action :set_clear, only: [:show, :edit, :update, :destroy]
|
7
|
-
|
8
|
-
# GET /clears
|
9
|
-
def index
|
10
|
-
@clears = Clear.all
|
11
|
-
end
|
12
|
-
|
13
|
-
# GET /clears/1
|
14
|
-
def show
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
# Use callbacks to share common setup or constraints between actions.
|
19
|
-
def set_clear
|
20
|
-
@clear = Clear.find(params[:id])
|
21
|
-
end
|
22
|
-
|
23
|
-
# Only allow a list of trusted parameters through.
|
24
|
-
def clear_params
|
25
|
-
params.require(:clear).permit(:ip, :result, :answer, :threat_before, :threat_after)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
1
|
+
require_dependency "antispam/application_controller"
|
2
|
+
|
3
|
+
module Antispam
|
4
|
+
class ClearsController < ApplicationController
|
5
|
+
before_action :must_be_admin
|
6
|
+
before_action :set_clear, only: [:show, :edit, :update, :destroy]
|
7
|
+
|
8
|
+
# GET /clears
|
9
|
+
def index
|
10
|
+
@clears = Clear.all
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /clears/1
|
14
|
+
def show
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
# Use callbacks to share common setup or constraints between actions.
|
19
|
+
def set_clear
|
20
|
+
@clear = Clear.find(params[:id])
|
21
|
+
end
|
22
|
+
|
23
|
+
# Only allow a list of trusted parameters through.
|
24
|
+
def clear_params
|
25
|
+
params.require(:clear).permit(:ip, :result, :answer, :threat_before, :threat_after)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
|
-
require_dependency "antispam/application_controller"
|
2
|
-
|
3
|
-
module Antispam
|
4
|
-
class ValidateController < ApplicationController
|
5
|
-
def index
|
6
|
-
respond_to do |format|
|
7
|
-
format.html
|
8
|
-
format.js { render js: 'window.location = "/antispam/validate"'}
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
1
|
+
require_dependency "antispam/application_controller"
|
2
|
+
|
3
|
+
module Antispam
|
4
|
+
class ValidateController < ApplicationController
|
5
|
+
def index
|
6
|
+
respond_to do |format|
|
7
|
+
format.html
|
8
|
+
format.js { render js: 'window.location = "/antispam/validate"'}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Antispam
|
2
|
-
module ApplicationHelper
|
3
|
-
end
|
4
|
-
end
|
1
|
+
module Antispam
|
2
|
+
module ApplicationHelper
|
3
|
+
end
|
4
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Antispam
|
2
|
-
module BlocksHelper
|
3
|
-
end
|
4
|
-
end
|
1
|
+
module Antispam
|
2
|
+
module BlocksHelper
|
3
|
+
end
|
4
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Antispam
|
2
|
-
module ChallengesHelper
|
3
|
-
end
|
4
|
-
end
|
1
|
+
module Antispam
|
2
|
+
module ChallengesHelper
|
3
|
+
end
|
4
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Antispam
|
2
|
-
module ClearsHelper
|
3
|
-
end
|
4
|
-
end
|
1
|
+
module Antispam
|
2
|
+
module ClearsHelper
|
3
|
+
end
|
4
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Antispam
|
2
|
-
class ApplicationJob < ActiveJob::Base
|
3
|
-
end
|
4
|
-
end
|
1
|
+
module Antispam
|
2
|
+
class ApplicationJob < ActiveJob::Base
|
3
|
+
end
|
4
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
module Antispam
|
2
|
-
class ApplicationMailer < ActionMailer::Base
|
3
|
-
default from: 'from@example.com'
|
4
|
-
layout 'mailer'
|
5
|
-
end
|
6
|
-
end
|
1
|
+
module Antispam
|
2
|
+
class ApplicationMailer < ActionMailer::Base
|
3
|
+
default from: 'from@example.com'
|
4
|
+
layout 'mailer'
|
5
|
+
end
|
6
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
module Antispam
|
2
|
-
class ApplicationRecord < ActiveRecord::Base
|
3
|
-
self.abstract_class = true
|
4
|
-
end
|
5
|
-
end
|
1
|
+
module Antispam
|
2
|
+
class ApplicationRecord < ActiveRecord::Base
|
3
|
+
self.abstract_class = true
|
4
|
+
end
|
5
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Antispam
|
2
|
-
class Block < ApplicationRecord
|
3
|
-
end
|
4
|
-
end
|
1
|
+
module Antispam
|
2
|
+
class Block < ApplicationRecord
|
3
|
+
end
|
4
|
+
end
|
@@ -1,26 +1,26 @@
|
|
1
|
-
module Antispam
|
2
|
-
class Challenge < ApplicationRecord
|
3
|
-
before_create :generate
|
4
|
-
|
5
|
-
def generate
|
6
|
-
self.question = create_string
|
7
|
-
self.answer = self.question
|
8
|
-
end
|
9
|
-
def create_string
|
10
|
-
o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
|
11
|
-
(0...8).map { o[rand(o.length)] }.join
|
12
|
-
end
|
13
|
-
def get_image
|
14
|
-
require "image_processing/vips"
|
15
|
-
image = Vips::Image.text(self.answer, dpi: 300)
|
16
|
-
image.draw_line(255, 5+rand(20).to_i, 5+rand(20).to_i, 150+rand(50).to_i, 10+rand(10).to_i)
|
17
|
-
end
|
18
|
-
def validate?(check)
|
19
|
-
return false if self.answer.nil?
|
20
|
-
result = false
|
21
|
-
result = true if self.answer.downcase == check.downcase
|
22
|
-
self.update_column(:answer,nil)
|
23
|
-
return result
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
1
|
+
module Antispam
|
2
|
+
class Challenge < ApplicationRecord
|
3
|
+
before_create :generate
|
4
|
+
|
5
|
+
def generate
|
6
|
+
self.question = create_string
|
7
|
+
self.answer = self.question
|
8
|
+
end
|
9
|
+
def create_string
|
10
|
+
o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
|
11
|
+
(0...8).map { o[rand(o.length)] }.join
|
12
|
+
end
|
13
|
+
def get_image
|
14
|
+
require "image_processing/vips"
|
15
|
+
image = Vips::Image.text(self.answer, dpi: 300)
|
16
|
+
image.draw_line(255, 5+rand(20).to_i, 5+rand(20).to_i, 150+rand(50).to_i, 10+rand(10).to_i)
|
17
|
+
end
|
18
|
+
def validate?(check)
|
19
|
+
return false if self.answer.nil?
|
20
|
+
result = false
|
21
|
+
result = true if self.answer.downcase == check.downcase
|
22
|
+
self.update_column(:answer,nil)
|
23
|
+
return result
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Antispam
|
2
|
-
class Clear < ApplicationRecord
|
3
|
-
end
|
4
|
-
end
|
1
|
+
module Antispam
|
2
|
+
class Clear < ApplicationRecord
|
3
|
+
end
|
4
|
+
end
|
data/app/models/antispam/ip.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
|
-
module Antispam
|
2
|
-
class Ip < ApplicationRecord
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module Antispam
|
2
|
+
class Ip < ApplicationRecord
|
3
|
+
after_initialize :set_default_expires_at
|
4
|
+
def expired?
|
5
|
+
self.expires_at < Time.now
|
6
|
+
end
|
7
|
+
private
|
8
|
+
def set_default_expires_at
|
9
|
+
self.expires_at ||= 24.hours.from_now
|
10
|
+
end
|
11
|
+
end
|
7
12
|
end
|
@@ -1,39 +1,39 @@
|
|
1
|
-
<p id="notice"><%= notice %></p>
|
2
|
-
|
3
|
-
<div class="row">
|
4
|
-
<div class="cx">
|
5
|
-
<h1>Blocks</h1>
|
6
|
-
|
7
|
-
<table>
|
8
|
-
<thead>
|
9
|
-
<tr>
|
10
|
-
<th>Ip</th>
|
11
|
-
<th>Provider</th>
|
12
|
-
<th>Controllername</th>
|
13
|
-
<th>Actionname</th>
|
14
|
-
<th>Threat</th>
|
15
|
-
<th colspan="3"></th>
|
16
|
-
</tr>
|
17
|
-
</thead>
|
18
|
-
|
19
|
-
<tbody>
|
20
|
-
<% Antispam::Block.all.order(created_at: :desc).limit(50).each do |block| %>
|
21
|
-
<tr>
|
22
|
-
<td><%= block.ip %></td>
|
23
|
-
<td><%= block.provider %></td>
|
24
|
-
<td><%= block.controllername %></td>
|
25
|
-
<td><%= block.actionname %></td>
|
26
|
-
<td><%= block.threat %></td>
|
27
|
-
<td><%= time_ago_in_words block.created_at %> ago</td>
|
28
|
-
<!-- <td><%#= link_to 'Show', block %></td>-->
|
29
|
-
<!-- <td><%#= link_to 'Edit', edit_block_path(block) %></td>-->
|
30
|
-
<!-- <td><%#= link_to 'Destroy', block, method: :delete, data: { confirm: 'Are you sure?' } %></td>-->
|
31
|
-
</tr>
|
32
|
-
<% end %>
|
33
|
-
</tbody>
|
34
|
-
</table>
|
35
|
-
</div>
|
36
|
-
<div class="cx">
|
37
|
-
<%= render template: '/antispam/clears/index', formats: :html %>
|
38
|
-
</div>
|
1
|
+
<p id="notice"><%= notice %></p>
|
2
|
+
|
3
|
+
<div class="row">
|
4
|
+
<div class="cx">
|
5
|
+
<h1>Blocks</h1>
|
6
|
+
|
7
|
+
<table>
|
8
|
+
<thead>
|
9
|
+
<tr>
|
10
|
+
<th>Ip</th>
|
11
|
+
<th>Provider</th>
|
12
|
+
<th>Controllername</th>
|
13
|
+
<th>Actionname</th>
|
14
|
+
<th>Threat</th>
|
15
|
+
<th colspan="3"></th>
|
16
|
+
</tr>
|
17
|
+
</thead>
|
18
|
+
|
19
|
+
<tbody>
|
20
|
+
<% Antispam::Block.all.order(created_at: :desc).limit(50).each do |block| %>
|
21
|
+
<tr>
|
22
|
+
<td><%= block.ip %></td>
|
23
|
+
<td><%= block.provider %></td>
|
24
|
+
<td><%= block.controllername %></td>
|
25
|
+
<td><%= block.actionname %></td>
|
26
|
+
<td><%= block.threat %></td>
|
27
|
+
<td><%= time_ago_in_words block.created_at %> ago</td>
|
28
|
+
<!-- <td><%#= link_to 'Show', block %></td>-->
|
29
|
+
<!-- <td><%#= link_to 'Edit', edit_block_path(block) %></td>-->
|
30
|
+
<!-- <td><%#= link_to 'Destroy', block, method: :delete, data: { confirm: 'Are you sure?' } %></td>-->
|
31
|
+
</tr>
|
32
|
+
<% end %>
|
33
|
+
</tbody>
|
34
|
+
</table>
|
35
|
+
</div>
|
36
|
+
<div class="cx">
|
37
|
+
<%= render template: '/antispam/clears/index', formats: :html %>
|
38
|
+
</div>
|
39
39
|
</div>
|
@@ -1,24 +1,24 @@
|
|
1
|
-
<p id="notice"><%= notice %></p>
|
2
|
-
|
3
|
-
<p>
|
4
|
-
<strong>Ip:</strong>
|
5
|
-
<%= @block.ip %>
|
6
|
-
</p>
|
7
|
-
|
8
|
-
<p>
|
9
|
-
<strong>Provider:</strong>
|
10
|
-
<%= @block.provider %>
|
11
|
-
</p>
|
12
|
-
|
13
|
-
<p>
|
14
|
-
<strong>Controllername:</strong>
|
15
|
-
<%= @block.controllername %>
|
16
|
-
</p>
|
17
|
-
|
18
|
-
<p>
|
19
|
-
<strong>Actionname:</strong>
|
20
|
-
<%= @block.actionname %>
|
21
|
-
</p>
|
22
|
-
|
23
|
-
<%= link_to 'Edit', edit_block_path(@block) %> |
|
24
|
-
<%= link_to 'Back', blocks_path %>
|
1
|
+
<p id="notice"><%= notice %></p>
|
2
|
+
|
3
|
+
<p>
|
4
|
+
<strong>Ip:</strong>
|
5
|
+
<%= @block.ip %>
|
6
|
+
</p>
|
7
|
+
|
8
|
+
<p>
|
9
|
+
<strong>Provider:</strong>
|
10
|
+
<%= @block.provider %>
|
11
|
+
</p>
|
12
|
+
|
13
|
+
<p>
|
14
|
+
<strong>Controllername:</strong>
|
15
|
+
<%= @block.controllername %>
|
16
|
+
</p>
|
17
|
+
|
18
|
+
<p>
|
19
|
+
<strong>Actionname:</strong>
|
20
|
+
<%= @block.actionname %>
|
21
|
+
</p>
|
22
|
+
|
23
|
+
<%= link_to 'Edit', edit_block_path(@block) %> |
|
24
|
+
<%= link_to 'Back', blocks_path %>
|
@@ -1,32 +1,32 @@
|
|
1
|
-
<%= form_with(model: challenge) do |form| %>
|
2
|
-
<% if challenge.errors.any? %>
|
3
|
-
<div id="error_explanation">
|
4
|
-
<h2><%= pluralize(challenge.errors.count, "error") %> prohibited this challenge from being saved:</h2>
|
5
|
-
|
6
|
-
<ul>
|
7
|
-
<% challenge.errors.each do |error| %>
|
8
|
-
<li><%= error.full_message %></li>
|
9
|
-
<% end %>
|
10
|
-
</ul>
|
11
|
-
</div>
|
12
|
-
<% end %>
|
13
|
-
|
14
|
-
<div class="field">
|
15
|
-
<%= form.label :question %>
|
16
|
-
<%= form.text_field :question %>
|
17
|
-
</div>
|
18
|
-
|
19
|
-
<div class="field">
|
20
|
-
<%= form.label :answer %>
|
21
|
-
<%= form.text_field :answer %>
|
22
|
-
</div>
|
23
|
-
|
24
|
-
<div class="field">
|
25
|
-
<%= form.label :code %>
|
26
|
-
<%= form.text_field :code %>
|
27
|
-
</div>
|
28
|
-
|
29
|
-
<div class="actions">
|
30
|
-
<%= form.submit %>
|
31
|
-
</div>
|
32
|
-
<% end %>
|
1
|
+
<%= form_with(model: challenge) do |form| %>
|
2
|
+
<% if challenge.errors.any? %>
|
3
|
+
<div id="error_explanation">
|
4
|
+
<h2><%= pluralize(challenge.errors.count, "error") %> prohibited this challenge from being saved:</h2>
|
5
|
+
|
6
|
+
<ul>
|
7
|
+
<% challenge.errors.each do |error| %>
|
8
|
+
<li><%= error.full_message %></li>
|
9
|
+
<% end %>
|
10
|
+
</ul>
|
11
|
+
</div>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<div class="field">
|
15
|
+
<%= form.label :question %>
|
16
|
+
<%= form.text_field :question %>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<div class="field">
|
20
|
+
<%= form.label :answer %>
|
21
|
+
<%= form.text_field :answer %>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<div class="field">
|
25
|
+
<%= form.label :code %>
|
26
|
+
<%= form.text_field :code %>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<div class="actions">
|
30
|
+
<%= form.submit %>
|
31
|
+
</div>
|
32
|
+
<% end %>
|
@@ -1,6 +1,6 @@
|
|
1
|
-
<h1>Editing Challenge</h1>
|
2
|
-
|
3
|
-
<%= render 'form', challenge: @challenge %>
|
4
|
-
|
5
|
-
<%= link_to 'Show', @challenge %> |
|
6
|
-
<%= link_to 'Back', challenges_path %>
|
1
|
+
<h1>Editing Challenge</h1>
|
2
|
+
|
3
|
+
<%= render 'form', challenge: @challenge %>
|
4
|
+
|
5
|
+
<%= link_to 'Show', @challenge %> |
|
6
|
+
<%= link_to 'Back', challenges_path %>
|