I manually define a path in a rails helper as I had some conflicts when using a slug for the url. It's been working for a while quite well but now I suddenly keep getting a "wrong number of arguments (1 for 0)" error for it.
In the articles helper:
def edit_article_path()
"/articles/#{#article.id}/edit"
end
Any help will be much appreciated.
You should not rely on the #article variable because your method is a helper, which can be accessed everywhere in your views, and some (most?) views might not have the #article variable set.
I recommend you to use this implementation instead:
def edit_article_path(article)
"/articles/#{article.try(:id) || article}/edit"
end
Use it like this:
# view
link_to article.title, edit_article_path(article)
# or
link_to article.title, edit_article_path(article.id)
Related
I've been using HAML for over 10 years, and this simple use case continues to elude me.
Say I have the following haml code
- links.each do |link|
= link_to link.url do
%i.fa.fa-map
= link.text
This block works while looping only, but imagine a situation where I want to reuse the block in multiple loops, or in multiple places in the HAML file. I do not currently know how to do that without creating a separate partial or helper. When the block is big enough, I often will create a partial, but often the block is small and a partial seems tedious overkill. Sometimes I have several blocks like this that I only want re-used in one HAML file.
I tried first to create this with content_for but it doesn't accept arguments and can't be cached.
My second attempt was with capture_haml, but I think that has to be called directly indide of HAML, not a ruby method. The following obviously fails for syntax reasons, but you see what I'm trying to do:
:ruby
def entry_link(url, text)
capture_haml(url, text) do |url, text|
= link_to url do
%i.fa.fa-map
text
end
end
Update:
I was able to get this far, which is functional but ugly AF.
:ruby
def entry_link(url, text)
capture_haml(url, text) do |url, text|
link_to url do
haml_tag :i, {class: 'fa fa-map'}
haml_concat(text)
end
end
end
= entry_link('/', 'My Link')
The following would be a more acceptable syntax, but I get the strange error undefined local variable or method _hamlout'`
- def entry_link(url, text)
- link_to url do
%i.fa.fa-map
text
Apologies for such a simple question, but I couldn't been able to solve it myself after hours since my RoR knowledge is basically nonexistent. In the Rails application I'm working with, has been used a navigation helper to highlight active menu:
def nav_link(link_text, link_path, ico_path)
class_name = current_page?(link_path) ? 'active' : nil
content_tag :li do
link_to(link_path, class: class_name) do
image_tag("icons/#{ico_path}.svg") + content_tag(:span, link_text)
end
end
end
The circumstances have changed and current_page? is no longer a viable option, since routing now handled on the front-end. Is there a way to achieve the same functionality by retrieving, for instance, current url and check it against link_path?. I've tried a lot of things with different helpers like request.original_url, but to no avail.
request.original_url should work according to the documentation.
Returns the original request URL as a string
http://apidock.com/rails/ActionDispatch/Request/original_url
You could also try string concatenation with different variables.
request.host + request.full_path
If that doesn't work either, you could try
url_for(:only_path => false);
Use
request.url
http://api.rubyonrails.org/classes/ActionDispatch/Http/URL.html#method-i-url
or
request.path
http://www.rubydoc.info/gems/rack/Rack/Request#path-instance_method
You'll want to look at the active_link_to gem:
def nav_link(link_text, link_path, ico_path)
content_tag :li do
active_link_to link_path do
image_tag("icons/#{ico_path}.svg") + content_tag(:span, link_text)
end
end
end
Unlike the current_page? helper, active_link_to uses controller actions and model objects to determine whether you're on a specific page.
current_page? only tests against the current path, leaving you exposed if you're dealing with obscure or ajaxified routes.
--
I was going to write about how current_page? works etc, but since you mentioned that it's nonviable, I won't. I would have to question why it's nonviable though...
routing now handled on the front-end.
Surely even if you're using something like Angular with Rails, you'd have to set the routes for your app?
another pretty general question about Ruby on rails:
def destroy
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.destroy
redirect_to post_path(#post)
end
Looking at the find method, I call it with the parameter id (which is incoming through the REST request, I guess)
Now here
<%= link_to 'Destroy Comment', [comment.post, comment],
method: :delete,
data:{confirm: 'Are you sure?' } %>
I assemble the route with the id of both comment.post + comment. To me it seems like the comment.post.id and comment.id are given implicitly (magic^^), which is fine for me, but I tried to code it, and I get an exception.
Why is it that way? And can somebody guide me to the right part of the documentation where exactly this behavior is described? Im pretty lost with all this smart and automatic stuff ruby does....
Thanks!
You're confusing two very different things.
This is doing a request to ActiveRecord to find an instance of Post with a matching id:
Post.find(id)
This next line is using the built in UrlHelper to construct an HTML link in your view for the given resource:
link_to 'Link Text', resource
In your particular case, you specify the :method as being :delete. Through the configuration in your routes.rb file, rails then maps this DELETE request for a [POST, Comment] nested resource to the posts_comment_path and passes in the post_id for comment.post and the id for comment.
This isn't so magic if you dig through the Rails source code a little. The link_to documentation states that the second argument can accept any valid options accepted by url_for. (click here for link_to docs)
The url_for documentation (available here) says this:
<%= url_for(#workshop) %>
# calls #workshop.to_param which by default returns the id
# => /workshops/5
# to_param can be re-defined in a model to provide different URL names:
# => /workshops/1-workshop-name
So, not so magic really. It's definitely worth spending a little time following the chain of calls that rails makes when you call something like link_to as it demystifies a lot of what you initially see as quite complex.
all, I'm trying to get a custom action to work with a put method: in the
in _post.html.erb i have a link_to statement:
<%= link_to 'End now', post, :method => :put, :action => endnow %>
routes.rb contains:
resources :posts do
member do
put :endnow
end
and posts_controller.rb looks like:
class PostsController < ApplicationController
helper_method :endnow
[.. code for create, edit, destroy, etc ..]
def endnow
puts params
end
end
rake routes's relevant line looks like:
endnow_post PUT /posts/:id/endnow(.:format) posts#endnow
However, the action endnow helper doesn't run when clicking on this link.
Strangely, it does run with an index action (which i can tell from the puts command.
Of course, eventually the code for endnow will update #post, but for now, it just doesn't run properly.
Maybe i'm going about this the wrong way - all I'm trying to achieve is to update #post upon clicking the link to that post, and before showing it.
Any ideas / Alternatives?
Why not use the route helper method provided to you? Change your link to
<%= link_to 'End now', endnow_post_path(#post), method: :put %>
Things you're doing wrong:
If you want to specify the :action, use the Symbol for the action (you're missing a colon). :action => endnow should be action: :endnow
I will assume you have a #post instance variable you're passing from your controller to your action. You should be using that instead of post (unless you do in fact have a local post variable you're omitting from your code)
You are using endnow as an action; you should remove the helper_method :endnow line in your controller because it's not something you want to/should be accessing from your view.
This can all be avoided by using the route helper (for endnow_post you'd append _path to get the local route path: endnow_post_path), and pass in your #post as an argument.
Because you're trying to do a PUT request, you must make sure you have something like jquery-ujs included in your asset pipeline to convert these links to form submissions behind the scenes; browsers don't support PUT via the click of a link on their own.
As for why you're getting the template error when you get your link_to working, Rails is telling you that you need to create a app/views/posts/endnow.html.erb file. Your action has only puts params which does not terminate execution, leaving Rails to assume you still are trying to render some endnow.html.erb template.
Are there other ways to do what you're trying to do (change a single attribute of a specific model)? Sure. Are there better ways? That's pretty subjective; it may not be the most RESTful way, but it's arguably easier to deal with (if for example there are very specific authorization rules to check before updating the attribute you are modifying in endnow. Does the way you've started fleshing out work? Absolutely.
Finally, as a bump in the right direction, after you fix your link_to and remove the the helper_method as I have described above, your endnow action might look like this:
def endnow
post = Post.find!(params[:id])
post.some_attribute_here = some_new_value_here
post.save
redirect_to :root and return # <- this line sets a redirect back to your homepage and terminates execution, telling rails to do the redirect and **not** to render some endnow.html.erb file
end
i am trying to make nice helpers so that i can use these style:
edit(category)
destroy(post.comment.first)
show(#user)
and we get the selected link with a nice image.
can anyone tell me if i am doing it right or is there a better magical rails way to get the url?
def show(object)
link_to image_tag("admin/show.png"), eval("admin_{object.class.to_s.downcase}_path(# {object.id})")
end
def edit(object)
link_to image_tag("admin/edit.png"), eval("edit_admin_#{object.class.to_s.downcase}_path(#{object.id})")
end
def destroy(object)
link_to image_tag("admin/destroy.png"), eval("admin_#{object.class.to_s.downcase}_path(#{object.id})"), :method=>:delete, :confirm=>"Do you really want to delete this?"
end
this is working fine but i am looking for the magic rails way :-)
replace eval with send, and replace downcase with underscore which is rails' convention
send("admin_{object.class.to_s.underscore}_path", object.id)
BTW, rails can do these for you:
# equals to your `show(object)`
link_to image_tag('admin/show.png'), [:admin, object]