How do I access helpers I've written in Rails? - ruby-on-rails

I've written a helper for my user model in user_helper.rb
module UserHelper
def get_array_of_names_and_user_ids
User.all(&:first_name) + User.all.map(&:user_id)
end
end
Unfortunately when I type in
<div class="field">
<%= f.label :assignee, "Assigned to" %>
<%= select(:task, :assignee_id, User.get_array_of_names_and_user_ids )%>
</div>
It can't see it. Where am I going wrong? I'm using devise.

You're close. The helper doesn't become a class method like that -- it becomes accessible as a method in your views. Just simply call get_array_of_names_and_user_ids.

Helpers are for views not for model.
For model you should define class methods in User model
class User
def self.get_array_of_names_and_user_ids
User.all(&:first_name) + User.all.map(&:user_id)
end
end

You don't need to hand code this helper as Rails provides a helper called collection_select for this purpose.
In your view simply add this:
<%= collection_select(:task, :assignee_id, User.all, :id, :first_name,
:prompt => true) %>
Note:
I am assuming you have a small set of users in your DB(<30). Otherwise, you have to use some other control to select users.

Helpers are methods that can be called in the view, not methods to be called on the model
Just call get_array_of_names_and_user_ids

Related

How to send values that are not related to a model

I have a Post model that have a title and content attributes.
I want to make it possible to tweet when the user creates a post like this.
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_area :content %>
<%= f.check_box :with_tweet %> # Error
<%= f.text_field :tweet %> # Error
<% end %>
This code fails, because there are no with_tweet and tweet attributes for Post.
I don't think query strings are good idea situation like this.
How should I send a information that is not related a model?
Define them as virtual attributes:
class Post < ActiveRecord::Base
...
attr_accessor :with_tweet, :tweet
...
end
attr_accessor will provide a getter and a setter method for with_tweet and tweet which should then be accessible to you through the #post object.
Further to Vee's answer, let me explain why you'd need it:
Every attribute in a Rails model is the result of using a Ruby
getter & setter - meaning that your model's attributes are
essentially just parts of a Ruby object, built when your class is
initialized
The problem you have is Ruby on Rails does not build any other
attributes other than the ones in your DB, meaning if you wanted to
track extra data, you'll have to use virtual attributes to let
the class know to populate those not in the db
attr_accessor is used to define those extra attributes

Ruby on Rails Dynamically generate field name in view using variable from view helper

In my view, let's say I have something like this:
<%= f.text_field :name_first %>
and another time this:
<%= f.text_field :name_last %>
Instead of hard-coding the field names, I want to dynamically generate them using a view helper method.
def category_name
#contact_info.category.name
end
def return_field_name
category_lower = category_name.downcase
":name"+category_lower
end
So now my view should have something like this:
<%= f.text_field return_field_name %>
Write:
def return_field_name
category_lower = category_name.downcase
"name#{category_lower}".to_sym
# but I'm sure that without #to_sym it should work as well
end
But if it will help you you should write only pure methods. IMHO it's very good practice.

Rails (3) validation of non-ActiveRecord field

I have a model with a corresponding form, for which I use ActiveRecord validations. At the bottom of the form I'd like to have a single confirmation checkbox which should not be persisted, but which must be checked for the form to be submitted. I'd also like any errors that stems from this checkbox not being checked to display alongside the ActiveRecord errors.
Now I could cobble something together in the controller manually, but I'm wondering if there is a built-in, cleaner way to handle this kind of situation?
I think you should add this in your model:
validates_acceptance_of :check_me
attr_accessor :check_me
attr_accessible :check_me # if you already have attr_accessible defined in your model
and this in your view:
<%= form_for #your_model do |f| %>
# some code
<%= f.check_box :check_me %>
<% end %>

Rails - default value in text_field but only for new_record?

On a Content model have an attribute named slug. When creating a new record, I want to use a helper to populate this field, but on an existing record I want to use the value from the database.
Currently I have:
<% if #content.new_record? %>
<%= f.text_field :slug, :value => "#{generate_slug(6)}" %>
<% else %>
<%= f.text_field :slug %>
<% end %>
But that seems a bit verbose. Is this the best way, or is there no other way? (Rails newb just trying to find the "Rails way" on issues I'm unsure of)
Edit
I should note that the helper is currently in /app/helpers/application_helper.rb Moved to be a private action in the Contents controller. David's answer worked great.
In your controller
#content.slug ||= generate_slug(6)
This will assign a value to the slug attribute if none is present
Then, in your view you can simply use
<%= f.text_field :slug %>
Options
Try after_initialize callback in your model.
Try creating a method in your model where you set defaults and call it in your new action in the controller. Also call this method if your create fails and you render new. Remember to set default only when no value exists by using the ||= operator.
Example to follow. I'm typing on phone!
I happen to use jQuery in my projects, so when I want some functionality like this, I usually use something like labelify. Then, I'd use something like <%= f.text_field :slug, :title => generate_slug(6) %>. (Hot tip, you don't need to put the #generate_slug call inside of a string if it returns something that will resolve to a string by itself, in fact it's more performant if you don't.)
If you don't want to go with jQuery approach, you might want to wrap this piece of logic in your model.
def Content < ActiveRecord::Base
def slug
self.new_record? ? self.slug_for_new_record : attributes[:slug]
end
private
def slug_for_new_record
# I don't know what you're doing in generate_slug, but it sounds model-
# related, so if so, put it here and not in a helper
end
end
If it really belongs in the view, still another option is to just make your Ruby a little bit more concise (you'll have to judge if this is more readable):
<%= f.text_field :slug, :value => (generate_slug(6) if #content.new_record?) %>
Don't forget the parens surrounding (generate_slug(6) if #content.new_record?). If you do, the if will be applied to the text_field, which is not what you want.
But there are still more ways to do it. The above line of code isn't great if your logic might change and you're pasting this code all over your rails project. When I wanted to add a 'required' class to my text fields but only if they were a new record (we had some legacy data that we didn't want to make people clean up), I created my own form builder with a required_field method that just called text_field and added a 'required' class if the item was a new record. This might seem like a work, but we have around 20 different forms, each with potentially multiple required fields, and it's a lot easier to change the business logic in one place. So if you really think this logic belongs in the view but you've got a ton of these lines of code and you don't want to have to change it in a million places, then FormBuilder is the way to go. I think this is in most cases prettier and more appropriate than a helper, but again, beauty is in the eye of the beholder. Here's my code somewhat adapted for your case:
# config/environment.rb
ActionView::Base.default_form_builder = NamespacesAreFun::FormBuilder
# lib/namespaces_are_fun/form_builder.rb
module NamespacesAreFun
class FormBuilder < ActionView::Helpers::FormBuilder
def slug_field(method, options = {})
opts = options.to_options
opts.merge!(:value => generate_slug) if self.object.new_record?
text_field(method, opts)
end
end
end
# views/.../your_view.html.erb
<%= f.slug_field :slug %>
Hopefully in all of these different approaches is one that fits your project.

How to list instances of a model and have a form to create an instance on the same view?

i have a model named 'chapter' (whose only attributes are 'name' and 'course__id') which belongs to "course" (and a course has_many chapters). on the course 'Show' view, I list all chapters for that course. Easy.
I want to add a form at the end of the list so that a user can easily create a new chapter.
so in my controller, I've added this:
#newchapter=#course.chapters.build
and the form on the view looks like this:
<% form_for([#course,#newchapter]) do |c| -%>
<%= c.label :name, "New Chapter" %>: <%= c.text_field :name %>
<%= c.submit 'Create' %>
<% end %>
(for the sake of clarity: it is outside of the #course.chapters.each block)
Now, the problem is that #course.chapters.size is the actual number of chapters + the empty one i created in the controller.
Is there a way to loop through all #course.chapters except the last (empty) one? or is there a better practice (i.e. not create #newchapter or not like this)?
thanks,
Pierre
You don't want to use #course.chapters.build here because this does add an empty chapter to the course. Instead you'll want to use Chapter.new and set the :course option like this.
#newchapter = Chapter.new(:course => #course)
It may not even be necessary to specify :course here depending on how you are using #newchapter.

Resources