Fix related content with custom URLs

Some CONSUL installations might want to customize their URLs. For
instance, Spanish institutions might want to use "/propuestas" instead
of "/proposals". In that case, it would be impossible to add proposals
as related content because the related contents controller assumed the
name of the model was part of the URL.

Using `recognize_path` instead of manually analyzing the URL solves the
issue.

Now that we don't call the `constantize` method on an empty string as we
previously did, we can be more specific in the `rescue` block and point
out that the only exception we expect is the one where users enter a
route which isn't recognized.
This commit is contained in:
Javi Martín
2021-06-23 04:36:37 +02:00
parent 48dc72cea9
commit 89a06ea6ef
2 changed files with 46 additions and 12 deletions

View File

@@ -7,7 +7,8 @@ class RelatedContentsController < ApplicationController
related_content = current_user.related_contents.new(
parent_relationable_id: params[:relationable_id],
parent_relationable_type: params[:relationable_klass],
child_relationable: related_object
child_relationable_id: child_relationable_params[:id],
child_relationable_type: child_relationable_params[:type]
)
if related_content.save
@@ -41,17 +42,23 @@ class RelatedContentsController < ApplicationController
params[:url].start_with?(Setting["url"])
end
def related_object
if valid_url?
url = params[:url]
def child_relationable_params
@child_relationable_params ||=
if valid_url?
related_params = Rails.application.routes.recognize_path(params[:url])
related_klass = url.scan(/\/(#{RelatedContent::RELATIONABLE_MODELS.join("|")})\//)
.flatten.map { |i| i.to_s.singularize.camelize }.join("::")
related_id = url.match(/\/(\d+)(?!.*\/\d)/)[1]
related_klass.singularize.camelize.constantize.find_by(id: related_id)
end
rescue
nil
if RelatedContent::RELATIONABLE_MODELS.include?(related_params[:controller].split("/").last)
{
id: related_params[:id],
type: related_params[:controller].split("/").map(&:singularize).join("/").classify
}
else
{}
end
else
{}
end
rescue ActionController::RoutingError
{}
end
end

View File

@@ -90,6 +90,33 @@ shared_examples "relationable" do |relationable_model_name|
expect(page).to have_content "Link not valid. You cannot relate a content to itself"
end
context "custom URLs" do
before do
custom_route = proc { get "/mypath/:id" => "debates#show" }
Rails.application.routes.send(:eval_block, custom_route)
end
after { Rails.application.reload_routes! }
scenario "finds relationable with custom URLs" do
related = create(:debate, title: "My path is the only one I've walked")
login_as(user)
visit relationable.url
click_button "Add related content"
within("#related_content") do
fill_in "Link to related content", with: "#{url}/mypath/#{related.id}"
click_button "Add"
end
within("#related-content-list") do
expect(page).to have_content "My path is the only one I've walked"
end
end
end
scenario "related content can be scored positively" do
related_content = create(:related_content, parent_relationable: relationable, child_relationable: related1, author: build(:user))