Skip to content

Commit b6497af

Browse files
committed
link and bookmark model validate URL
For the link controller, the error handling has been added. As the redaction system use ajax to update links, the controller return error result in JSON format. To handle validation errors correctly on client side, the edition_in_place client javascript has to handle ajax error event: when error is raised and response is JSON, event handler looks for error messages and display them in the "ul.error" HTML tag. Furthermore, the [`render text` has been deprecated](rails/rails#12374) I had to replace them with `render plain` for redaction locks.
1 parent 7e89d77 commit b6497af

File tree

10 files changed

+72
-21
lines changed

10 files changed

+72
-21
lines changed

app/assets/javascripts/edition_in_place.coffee

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ class EditionInPlace
4242
false
4343

4444
error: =>
45+
try
46+
error = @el.find("ul.error")
47+
response = $.parseJSON(@xhr.responseText)
48+
messages = []
49+
for attribute, errors of response.errors
50+
for message in errors
51+
messages.push(message)
52+
if messages.length == 1
53+
error.text("Erreur : " + messages[0])
54+
else
55+
error.text("Erreurs :")
56+
for message in messages
57+
error.append($("<li>").append(message))
58+
error.show()
4559
@el.trigger "in_place:error", @xhr
4660
@xhr = null
4761

app/assets/stylesheets/parts/content.scss

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ body#news-revision #contents,
1313
body#boards-show #contents,
1414
body#stylesheets-edit #contents,
1515
body#wiki_pages-changes #contents,
16-
body#admin-index #container > ul {
16+
body#admin-index #container > ul,
17+
#redaction #new_link,
18+
#redaction .edit_link {
1719
display: block;
1820
background: white;
1921
padding: 10px $PX_PAD_NODE 10px $PX_PAD_NODE;

app/assets/stylesheets/parts/redaction.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,10 @@ body#redaction-index {
503503
}
504504
}
505505
}
506+
#new_link,
507+
.edit_link {
508+
padding: 5px;
509+
}
506510
input#link_title {
507511
width: 100%; // this rule force the input to not enlarge the #edition flex box
508512
}

app/controllers/redaction/links_controller.rb

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,29 @@ def new
1212
def create
1313
@link.attributes = link_params
1414
@link.user = current_user
15-
@link.save
16-
render partial: 'button'
15+
if @link.save
16+
render partial: 'button'
17+
else
18+
render status: :unprocessable_entity, json: { errors: @link.errors.as_json }
19+
end
1720
end
1821

1922
def edit
2023
if @link.lock_by(current_user)
2124
render partial: 'form'
2225
else
23-
render status: :forbidden, text: "Désolé, #{@link.locker} est déjà en train de modifier ce lien !"
26+
render status: :forbidden, plain: "Désolé, #{@link.locker} est déjà en train de modifier ce lien !"
2427
end
2528
end
2629

2730
def update
2831
@link.attributes = link_params
2932
@link.update_by(current_user)
30-
render @link
33+
if @link.destroyed? || @link.save
34+
render @link
35+
else
36+
render status: :unprocessable_entity, json: { errors: @link.errors.as_json }
37+
end
3138
end
3239

3340
def unlock

app/controllers/redaction/news_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def reorganize
5959
@news.put_paragraphs_together
6060
render :reorganize, layout: "chat_n_edit"
6161
else
62-
render status: :forbidden, text: "Désolé, un verrou a déjà été posé sur cette dépêche !"
62+
render status: :forbidden, plain: "Désolé, un verrou a déjà été posé sur cette dépêche !"
6363
end
6464
end
6565

app/controllers/redaction/paragraphs_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def edit
2525
if @paragraph.lock_by(current_user)
2626
render partial: 'form'
2727
else
28-
render status: :forbidden, text: "Désolé, #{@paragraph.locker} est déjà en train de modifier ce paragraphe !"
28+
render status: :forbidden, plain: "Désolé, #{@paragraph.locker} est déjà en train de modifier ce paragraphe !"
2929
end
3030
end
3131

app/models/bookmark.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class Bookmark < Content
2626
validates :title, presence: { message: "Le titre est obligatoire" },
2727
length: { maximum: 100, message: "Le titre est trop long" }
2828
validates :link, presence: { message: "Vous ne pouvez pas poster un lien vide" },
29+
http_url: { message: "Le lien n'est pas valide" },
2930
length: { maximum: 255, message: "Le lien est trop long" }
3031

3132
def create_node(attrs={})

app/models/link.rb

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ class Link < ActiveRecord::Base
2626

2727
validates :title, presence: { message: "Un lien doit obligatoirement avoir un titre" },
2828
length: { maximum: 100, message: "Le titre est trop long" }
29-
validates :url, presence: { message: "Un lien doit obligatoirement avoir une adresse" },
29+
validates :url, http_url: { protocols: PROTOCOLS, message: "L'adresse n'est pas valide" },
30+
presence: { message: "Un lien doit obligatoirement avoir une adresse" },
3031
length: { maximum: 255, message: "L’adresse est trop longue" }
31-
validate :authorized_protocol
3232

3333
def url=(raw)
3434
raw.strip!
@@ -39,17 +39,9 @@ def url=(raw)
3939
uri = URI.parse(raw)
4040
end
4141
write_attribute :url, uri.to_s
42-
end
43-
44-
def authorized_protocol
45-
if url.blank?
46-
errors.add(:url, "L’adresse est obligatoire")
47-
else
48-
uri = URI.parse(url)
49-
return true if PROTOCOLS.include?(uri.scheme)
50-
return true if uri.scheme.nil? && uri.host == MY_DOMAIN
51-
errors.add(:url, "L’adresse d’un lien n’est pas valide")
52-
end
42+
# Let raw value if error when parsed, HttpUrlValidator will manage it
43+
rescue URI::InvalidURIError
44+
write_attribute :url, raw
5345
end
5446

5547
### Behaviour ###
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Validate if a value is a HTTP url
2+
class HttpUrlValidator < ActiveModel::EachValidator
3+
def validate_each(record, attribute, value)
4+
if value.present? && not(valid?(value, options))
5+
record.errors.add attribute, (options[:message] || "n'est pas une URL HTTP valide")
6+
end
7+
end
8+
9+
private
10+
11+
def valid?(value, options)
12+
uri = URI.parse(value)
13+
if uri.scheme.blank? && uri.host.blank?
14+
value = "http://#{value}"
15+
uri = URI.parse(value)
16+
end
17+
if options.has_key?(:protocols)
18+
return true if options[:protocols].include?(uri.scheme)
19+
end
20+
uri.scheme.nil? && uri.host == MY_DOMAIN
21+
rescue URI::InvalidURIError
22+
false
23+
end
24+
end
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
= form_for [:redaction, @link] do |form|
22
- if @link.new_record?
33
%input(type="hidden" name="news_id" value="#{@news.id}")
4-
%p.link
4+
%div.link
55
= form.text_field :title, maxlength: 100, autocomplete: "off", placeholder: 'Titre'
66
= form.url_field :url, autocomplete: "off", placeholder: 'Adresse'
77
= form.select :lang, Lang.all
8+
%br
9+
%ul.error(style="display: none")
810
- if @link.persisted?
911
%button.cancel{'data-url' => unlock_redaction_link_path(@link), type: "button"} Annuler
12+
- else
13+
%button.cancel{type: "button"} Annuler
1014
= form.submit "OK"
15+
- if @link.persisted?
16+
%p
17+
Note: pour supprimer le lien, videz le champ Adresse et cliquez sur OK

0 commit comments

Comments
 (0)