Formtastic set class in all forms - ruby-on-rails

There's a way to add a class attribute in all the forms using formtastic?
I don't want to edit every form using something like this:
<% semantic_form_for #meetingsearch, :html => { :class => "my_class", :id => "my_id" } do |f| %>

You can set the default form class in the initializer:
Formtastic::Helpers::FormHelper.default_form_class = "my_class"

I do not believe there is a built-in way to do this. My recommendation is to create a new definition for semantic_form_for in which you add the :class to the original semantic_form_for.
Overriding a method, or making a new method, or changing the original source all seems more effort then a simple grep and replace of the views. A good text editor should easily search the files and add a :class declaration to all the semantic_form_for lines.
I know it isn't a DRY as you were hoping for an answer but I don't think there is any easy way to do this as you expected.
On a side note you can do this for inputs. I made several custom inputs which were nothing more then the stock inputs with a :class attribute added. I don't thing there is the same kind of setup for the form itself though.

Related

Is a link_to a custom route or a form the best way to provide state change?

What is the 'Rails way' to provide access to methods such as the following from a view
def approve!
self.update_attribute status, 'approved'
end
Is it best to create a link to a custom route
<%= link_to 'Approve', approve_object_path(#object) %>
#objects_controller.rb
def approve
#object.approve!
end
Or to create an update form
<%= simple_form_for #object do |f| %>
<%= f.input :status, input_html { value: 'approved' }, as: :hidden %>
<%= f.submit %>
<% end %>
On the one hand, using a form and not using the approve! method at all seems to align better with restful routes.
On the other hand, a link to a custom route seems to provide less opportunity for submitted values to be manipulated by the user, and also requires less code to implement.
Which is the preferred way to do this?
I don't know if there's a preferred best practice, per se...
Just my opinion, but I normally do the link_to approach, and for an "state machine" like your example. The need for an entire form for a simple action like this is a lot of extra code that isn't necessary when an action can be called to change the state.
The counter argument to this is that it breaks CRUD, and requires a non-CRUD route. Convention over configuration champions would probably prefer an entire new controller to change the state of the object.
TL;DR - I do the link_to approach, and I use :remote => true to make it asynchronous so the page doesn't even reload (unless you need the page to redirect elsewhere).
You can change state remotely with both the scenarios.
But I think if only a state has to be changed then use link_to. As we don't need to have form features with listed attributes in params here.

How can I create a Rails form that POSTs to this custom route?

I have this route...
match '/set_current_location/:contract_id' => 'contracts#set_current_location',
:as => :set_current_location
I've written the ContractsController#set_current_location action and tests and that's all working as expected.
I'm having trouble with the view code.
I understand that this isn't The Rails Way, but because of the underlying DB structure (which I didn't create and am not allowed to change), it would be best in this one special case to not base the form on a model at all.
So my question is, how can I create a non-model form that posts to that route?
This should work for you:
<%= form_tag(set_current_location_path(contract_id), method: :post) do %>
...
<% end %>

How would I add a method to ActiveView::Helpers::FormHelper to be used with form_for?

I am currently making a plugin, and I would like to add a method to ActiveView::Helpers::FormHelper, Essentially, the plugin is a helper that will convert checkbox input into bitwise flags so when you do actions like new and update, you can continue to pass in a params hash, and my plugin will pull out the checkbox data and convert it into a single number representing the flag state. Anyway, I want to be able to do something like this:
<% form_for #person do |f| %>
<%= f.check_boxes_for_flags %>
<% end %>
Which would create checkboxes in the HTML and then set them accordingly to the flags. I know how to add an instance method to ActiveView::Helpers::FormHelper, but I'm not sure how to access #person from this method. Any ideas?
Why wouldn't you use:
<%= f.check_boxes_for_flags :country %>
That way you can create your extension similar to how the ActiveView helpers work.
Take a look at how check_box_tag in the rails source code gets the name from the model. Try to follow the conventions set forth by the framework, it makes things easier for you and those who will maintain your code after you.

Getting form_tag ids for Javascript Helpers

I'm sure my title was hugely unhelpeful, I'll try and describe my problem better here. Essentially, I have a bunch of form tags, actually I'm using formtastic, so they look kinda like this:
<%= f.inputs :email, :pass, :passconf, :for => :register_attributes %>
These generate a group of input fields and labels with rather long id names, e.g. one such field is called 'posting_register_attributes_email'.
Now, I'd like to create a link that hides/shows these elements on request. It's easy to do brute force, e.g.:
<%= link_to_function "Register", "$('#posting_register_attributes_email').hide()" %>
But I feel surely there must be a more elegant way of doing it than typing out the full generated name, is there a helper that will let me doing something like [:register_attributes][:email].hide or something to make this less tedious? I feel like there must be.
Thanks!
$("[id*='register_attributes']").hide();

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.

Resources