10

Current verbose rails path helpers

I'm constantly writing code to get URLs like:

link_to @applicant.name, company_job_applicant_path(@company, @job, @applicant)

However this code looks more like this (redundant) piece:

link_to @applicant.name, company_job_applicant_path(@applicant.job.company, @applicant.job, @applicant)

This is silly.

Required 'pert' path helpers

The other parameters can clearly be derived from the @job. All I should really need to type is:

link_to @applicant.name, applicant_quick_path @applicant

where there is a definition somewhere of:

def applicant_quick_path applicant
    company_job_applicant_path(applicant.job.company, applicant.job, applicant)
end

My questions

  1. Is this a reasonable Rails Way to do things
  2. Where should I store this method?
  3. I can currently access these helpers in the console using app.company_path. How would I access my new helper methods from the console?
Peter Nixey
  • 16,187
  • 14
  • 79
  • 133
  • The question marked as a duplicate is indeed similar, but this question is separate because it's answer has particulars to `link_to` view helper and the other is for routing and paths, rendering the details of the suggested solution different and affecting search-ability. – Peter DeWeese Dec 20 '18 at 20:44

2 Answers2

7

Yes, DRY is the "Rails way" to do things. If you're repeating this method over and over again, it makes sense to create a view helper for it. Instead of modifying the path helpers, I'd simply wrap rails link_to method.

You can do something quick and easy like this:

# app/helpers/application_helper.rb
def link_to_applicant(applicant)
  link_to applicant.name, company_job_applicant_path(applicant.job.company, applicant.job, applicant)
end

# link_to(@applicant)
#=> <a href="/companies/jobs/applicants/123">Peter Nixey</a>

Alternatively, you can roll in some extra support for the link_to method

def link_to_applicant(applicant, html_options={})
  link_to applicant.name, company_job_applicant_path(applicant.job.company, applicant.job, applicant), html_options
end

# link_to_applicant(@applicant, :id=>"applicant-#{@applicant.id}")
#=> <a id="applicant-123" href="companies/jobs/applicants/123">Peter Nixey</a>

If you want to fully support all the features provided by link_to, you can see how they permit for multiple function signatures here

# rails link_to source code
def link_to(*args, &block)
  if block_given?
    options      = args.first || {}
    html_options = args.second
    link_to(capture(&block), options, html_options)
  else
    name         = args[0]
    options      = args[1] || {}
    html_options = args[2]

    html_options = convert_options_to_data_attributes(options, html_options)
    url = url_for(options)

    href = html_options['href']
    tag_options = tag_options(html_options)

    href_attr = "href=\"#{html_escape(url)}\"" unless href
    "<a #{href_attr}#{tag_options}>#{html_escape(name || url)}</a>".html_safe
  end
end

RSpec notes

If you'd like to write tests for your view helpers in RSpec, follow this guide: https://www.relishapp.com/rspec/rspec-rails/docs/helper-specs/helper-spec

rodrigobdz
  • 47
  • 3
  • 13
maček
  • 76,434
  • 37
  • 167
  • 198
  • I actually need to do this for a more complex reason (see http://stackoverflow.com/questions/8424682/is-it-possible-to-dynamically-remove-a-level-of-rails-resource-nesting). Your answer was very helpful but on thinking about it I wonder how does one subsequently access those helpers in rspec tests e.g. when testing, `response.should redirect_to company_path(@company)`? I can't use the original long helper because there is actually logic going to be stored in my helpers... – Peter Nixey Dec 08 '11 at 17:55
  • 1
    I updated the answer with some RSpec notes – maček Dec 08 '11 at 19:07
  • Hi Macek, thanks for the helper testing reference. The thing I was wondering about though was not how to test the helpers but how to actually get access to them in other methods such as `something.should redirect_to my_helper_method(@company)` - thank you! – Peter Nixey Dec 08 '11 at 19:18
  • 2
    Also note that this way (in a helper) you wouldn't be able to use it in controllers. If you want this, you would have to move that method to application controller and declare it as a helper via `helper_method :link_to_applicant`. Then it will be available both in controller and view. – Dalibor Filus Dec 08 '11 at 19:22
1

You're describing a very typical Rails helper.

They go in app/helpers.

By default that directory will have an ApplicationHelper module, or you can add your own if you want to organize them differently.

jdl
  • 17,702
  • 4
  • 51
  • 54