Capybara find_link gives ambiguous match error - ruby-on-rails

<ul>
<% #topic.contents.each do |content| %>
<li>
<%= content.content %> <%= link_to "Edit", edit_content_path(content) %> <br><br>
</li>
<% end %>
</ul>
I need someway to test this using Capybara. I tried typing this in my test file:
test "there is an edit link on the show page" do
click_link "Enter"
click_link "Ruby"
assert find_link("Edit").first.visible?
end
But it winds up giving me a message:
1) Error:
VisitorFindContentTest#test_there_is_an_edit_link_on_the_show_page:
Capybara::Ambiguous: Ambiguous match, found 2 elements matching link "Edit"
test/integration/visitor_find_content_test.rb:44:in `block in <class:VisitorFindContentTest>'
What else can I do? What can be done? Should I do something to make each of my edits link unique? OR is there a capybara test method just that looks for the first appearance of an edit link?

Add an :id or a :class specific to the content as follows:
<%= content.content %> <%= link_to "Edit", edit_content_path(content), id: "content_#{content.id}" %> <br><br>
or
<%= content.content %> <span id: "content_#{content.id}"><%= link_to "Edit", edit_content_path(content) %></span> <br><br>
You can then use this id for clicking the link as follows (with the second option above):
content = Content.first # or some way of finding the required content object
within("#content_#{content.id}") do
click_link("Edit")
end

Related

why hobby_posts_path is not recognized by the system while it is there in rails routes

I'm following along a tutorial inn rails in which we can go the specific branch's category page but i m getting an error that the path sent on click event is not recognized by the app
the code for that page where i used that variable is
<% branch_path_name = "#{params[:action]}_posts_path " %>
<div class="col-sm-12">
<ul class="categories-list">
<%= render all_categories_button_partial_path, branch_path_name: branch_path_name %>
<%= #categories.each do |category | %>
<li class="category-item">
<%= link_to category.name, send(branch_path_name, category: category.name), :class => ("selected-item" if params[:category] == category.name) %>
</li>
<% end %>
</ul>
</div>
my all_categories_button_partial helper method is as follow
def all_categories_button_partial_path
if params[:category].blank?
'posts/branch/categories/all_selected'
else
'posts/branch/categories/all_not_selected'
end
end
and the partial i used inside my helper method are as _all_selected.html.erb
<li class="category-item">
<%= link_to "All", send(branch_path_name), :class => "selected-item" %>
</li>
and _all_not_selected.html.erb partial is
<li class="category-item">
<%= link_to "All", send(branch_path_name) %>
</li>
but when i click on the link then i got this error
undefined method `hobby_posts_path ' for #<#<Class:0x000000000e32de40>:0x000000000d3e1810>
Did you mean? hobby_posts_path
hobby_posts_url
Extracted source (around line #2):
1
2
3
<li class="category-item">
<%= link_to "All", send(branch_path_name), :class => "selected-item" %>
</li>
where i have done wrong?
Your path definition has an extra space. It currently is <% branch_path_name = "#{params[:action]}_posts_path " %>, while it should be <% branch_path_name = "#{params[:action]}_posts_path" %> (Notice the space is deleted after path)

Rails how to use link_to for an external website and also using a block?

I am trying to use link_to with block and also to link with an external web site, I already know how to use link_to to make my div clickable (learned from here) and also to use link_to to send user to another website (learned from here) but when I try to combine this two approches I got an error:
undefined method 'stringify_keys' for "www.google.com":String
Here is my html.erb code:
<%= link_to #slides[0].link, "#{#slides[0].link}", target: "_blank" do %>
<div class="carousel-item active">
<%= image_tag #slides[0].slide_image.thumb.url, class: "d-block w-100", alt: #slides[0].image_text %>
<div class="carousel-caption d-none d-md-block">
<h5><%= #slides[0].image_text %></h5>
</div>
</div>
<% end %>
I also tried:
<%= link_to #slides[0].link do %> # or
<%= link_to "#{#slides[0].link}", :target => "_blank" do %>
# I got the same error
<%= link_to url_for(#slides[0].link) do %>
# above I got localhost:3000/https://google.com insted of https://google.com
Does anyone know how to do this?
The link_to with block works like this:
link_to(url, html_options = {}) do
# block
end
link_to helper source
So you just have to do :
<%= link_to #slides[0].link, target: "_blank" do %>
#block
<% end %>
(assuming #slides[0].link == "https://google.com" i.e valid external url)

Render in a different order on the page breaks the routing

I have Challenges containing Puns, and it is possible to vote on puns. On the Challenge Show page, all puns are rendered and show their votes count. This is currently on the view page:
<%= render #challenge.puns.reverse %>
<br>
<div id="form">
<%= render "puns/form" %>
</div>
I want the puns form to appear above the items (puns) already submitted. But if swap them around, like this:
<div id="form">
<%= render "puns/form" %>
</div>
<%= render #challenge.puns.reverse %>
I get a controller error and pun.id is not suddenly not available and the voting link breaks.
No route matches {:action=>"upvote", :challenge_id=>"9", :controller=>"puns", :id=>nil}, missing required keys: [:id]
Here is the puns/form part that is causing the issue
<% if signed_in? %>
<% if current_user.voted_for? pun %>
<%= pun.votes_for.size %>
<span class="pun_text"><%= link_to pun.pun_text, challenge_pun_path(#challenge, pun.id) %></span>
<% else %>
<%= link_to like_challenge_pun_path(#challenge, pun.id), method: :put do %>
<span class="heart_like">❤</span> <%= pun.votes_for.size %>
<% end %>
<span class="pun_text"><%= link_to pun.pun_text, challenge_pun_path(#challenge, pun.id) %></span>
<% end %>
<% end %>
It is the like_challenge_pun_path that throws an error but I cannot understand why. I am declaring #challenge again here, so it should be able to get the id.
Here is the form for the puns:
<%= form_for([#challenge, #challenge.puns.build]) do |f| %>
<span class=".emoji-picker-container">
<%= f.text_area :pun_text, placeholder: "Add pun", data: { emojiable: true } %>
</span>
<%= f.submit %>
<% end %>
Also, here is my routes setup
resources :challenges do
resources :puns do
member do
put "like", to: "puns#upvote"
put "dislike", to: "puns#downvote"
end
end
end
and the corresponding action to upvote
def upvote
#pun = #challenge.puns.find(params[:id])
#pun.upvote_by current_user
redirect_to #challenge
end
Can anyone help?
I think the code is for the puns collection.
I assume the issue is that in the form you have something like:
#challenge.puns.build
So in #challenge.puns collection appears not persisted record (without id), so path for this model cannot be generated.
As a quick solution I suggest:
<%= render #challenge.puns.reverse.select(&:persisted?) %>
UPDATE:
As I assumed you have
<%= form_for([#challenge, #challenge.puns.build]) do |f| %>
You can also try:
<%= form_for([#challenge, Pun.new]) do |f| %>
Or solve it in the controller. But need to see controller code for it.

Rails link_to_if not hiding links correctly

For some reason my link_to_if line works, but appears on every show view for my model (Company).
Here's the code:
<% #customers.each do |customer| %>
<li>
<%= link_to_if customer.company_id == #company.id, "#{customer.first_name} #{customer.last_name}", customer_path(customer[:id]) %>
</li>
<% end %>
The issue: I have Customer1 linked to CompanyX. When I go to CompanyZ it shows Customer1, but the link is not a hyperlink. it's just plaintext, and not even supposed to be showing up. However on CompanyX's view, the link works fine. What am I doing wrong here?
If you read the documentation of link_to_if (https://apidock.com/rails/ActionView/Helpers/UrlHelper/link_to_if), it clearly says that [if false] only the name is returned.
In the doc you can find that the (optional) block given is rendered in the false case. So in your case you could pass it an empty block:
<%= link_to_if false, customer_path(customer[:id]) {} %>
In my opinion, if you want to display the link only if one or more customer(s) from #customers are associated to that #company, you should do it this way:
<% #customers.where(company_id: #company.id).each do |customer| %>
<li>
<%= link_to "#{customer.first_name} #{customer.last_name}", customer_path(customer[:id]) %>
</li>
<% %>
if you want to hide some records you can do from from controller to control customers based company
#customers = Company.find(:id).customers
then in your views you can just show it without to compare it
<% #customers.each do |customer| %>
<li>
<%= link_to "#{customer.first_name} #{customer.last_name}", customer_path(customer[:id]) %>
</li>
<% end %>

same rails path displays different template if flash messages are present

I came across an interesting problem when I try to alter what gets display if page is certain route'
<body>
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
<!---both logged_in and is_admin are in session_helper-->
<%if current_page?(login_path) or current_page?(signup_path)%>
<p class = "title">CLOUD SOLAR</p>
<% else %>
<% if logged_in?%>
<% if is_admin?%>
<%= link_to "All Users", users_path%>
<% end%>
<%= link_to "Settings", edit_user_path(current_user)%>
<%= link_to "Log Out", logout_path, method: "delete"%>
<% else %>
<%= link_to "Sign Up", signup_path%>
<%= link_to "Log in", login_path%>
<% end %>
<% end %>
<%= yield %>
<!-- <%=debug(params) if Rails.env.development?%> -->
</body>
In the code above, I am attempting to get rid of the "sign up" and "log in" link if the current page is either sign up or log in. The above code works fine until I test it with an incorrect email and password. When I test it with a wrong password, a flash message pops up (which it should!), but for some reason the Sign Up and Log in link also pops up underneath it also.
Given the code above, I thought that if the current route is login_path or signup_path, it will never get into the else part of the condition, but somehow it did.
What is going on here? Is the route somehow being altered when I input wrong information even though the url still displays localhost:3000/login or localhost:3000/signup ??
Edit: For clarification, the title disappears completely if the login form has some sort of error. What is replaced is a new login-form and a flash error message. Where did the title CLOUD SOLAR go?
You could try changing login_path and signup_path to login_url and signup_url. Another option would be to hardcode the paths.
current_page?(Rails.env.production? ? 'http://your_live_url/signup' : 'http://localhost:3000/signup')
Also, you could check the documentation here:
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-current_page-3F

Resources