semantic_fields_for doesn't group all into one li - ruby-on-rails

I'm using f.semantic_fields_for with haml
here is the current snippet.
%ul.documents
=f.semantic_fields_for :documents do |u|
= link_to(u.object.comment.presence || u.object.file.original_filename, u.object.file.url)
= u.input :comment, :as=>:string
= u.hidden_field :_destroy
= link_to_function image_tag("/img/del_documets.png"), "remove_fields(this)", :class => "btn"
the problem here is that only "u.input :comment, :as=>:string" is inside the "li" created by formtastic. The links and other fields get somewhere else and its kinda impossible to style correctly this broken html.
Is there anyway to make sure everything get inside the correct li?
Even if I add a li just after f.semantic_fields_for, it will only wrap the first link and the following elements will get wrapped only by the ul completely above.

It seems like formtastic always wraps inputs with <li> to avoid <fieldsets> to be inside <ol>, which is not valid.
Your best way around that is to put <li> around all your elements and add wrapper_html => { :class => :your_class } to your input if you like. That way you can style things your way.
I don't think you need the ul.documents around the inputs, semantic_fields_for already wraps everything using <ol>.
That't the thing with libraries that generate html directly, you'd better adapt your html and css to them instead of trying to make them generate your html.
I would do that (and style my own CSS from it):
=f.semantic_fields_for :documents do |u|
%ul.documents
%li= link_to(u.object.comment.presence || u.object.file.original_filename, u.object.file.url)
= u.input :comment, :as=>:string
%li= u.hidden_field :_destroy
%li= link_to_function image_tag("/img/del_documets.png"), "remove_fields(this)", :class => "btn"
Hope this helps.

You could also override the default behavior of Formtastic when it generates the inputs wrapper like this:
module Formtastic
module Inputs
module Base
module Wrapping
def input_wrapping(&block)
template.content_tag(:li,
[template.capture(&block), error_html, hint_html].join("\n").html_safe,
wrapper_html_options
)
end
end
end
end
end
Notice the content_tag(:li. You could replace it by content_tag(:div for example.
You know how to override module methods in Rails?

Related

Button "New Item" in Rails 4

I have a page that works with various models.
One of the items is "Language", where I select the language and level. But I can only insert a single language. I wonder what the best way to insert a "New" button to add another language, even if the edit page (because even though I need to include in the edit page too)
I'm using accepts_nested_attributes_for and simple_form.
Have tried several solutions but could not find any similar tutorial with what I need.
When you mention you have a page which works with various models, you need to remember views != models. In rails, views are used to show data you have defined in your controllers.
When you ask about inserting a new button to add a new language, this will be entirely dependent on your interface, and how you wish it to work. A good example would be this:
#app/views/languages/_new_lang.html.erb
<%= form_for Language.new, url: language_path do |f| %>
<%= f.text_field :name %>
<%= f.submit "Create" %>
<% end %>
A better way to do this will be to use ajax & render a layout-less element on your page:
#app/views/controller/your_view.html.erb
<%= button_to "Test", new_language_path, remote: true, id: "test" %>
#app/controllers/languages_controller.rb
Class LanaguageController < ActiveRecord::Base
layout Proc.new { |controller| controller.request.xhr? ? false : "application" }
end
#app/assets/javascripts/application.js.erb
$(document).on("ajax:success", "#test", function(data) {
$(data).appendTo("body");
});
This will allow you to send the required data through to your system to create a new language. Can be improved, so if you want to use it please let me know in the comments

Rails - custom helper repeating code with fields_for

I have created a custom helper in my application.rb file, which looks like:
module ApplicationHelper
def add_feature_field(feature_type, object_form_builder, actions_visible)
object_form_builder.object.features.build
fields = object_form_builder.fields_for :features do |features_builder|
render :partial => "features/fixed_feature", :locals => {:feature => features_builder, :fixed_feature_type => feature_type, :form_actions_visible => actions_visible}
end
end
end
I am calling this helper from my view like so:
<%= add_feature_field("First Name", customer, false) %>
<%= add_feature_field("Last Name", customer, false) %>
<%= add_feature_field("Date of Birth", customer, false) %>
This is working pretty much as anticipated, except for one major hurdle: the second time the helper is called, it renders 2 fields instead of a single field, and the third time it renders 3 fields.
I assume that what is happening is that the fields_for loop in my helper is picking up the previously built objects, and also rendering those - can anyone suggest a way of preventing this?
EDIT: For clarity, as per the comments, this helper method is being used within the Customer form; the Features being created are nested attributes.

Formtastic set class in all forms

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.

Creating classes for nested blocks in Ruby

I want to reformat some helpers in my Rails views. I want a syntax similar to:
<%=
box :option => 'value' do |b|
b.header "Header of box #1"
%>
Content of Box#1
<%
end
%>
The b.header call is optional.
How would I structure my code to allow this? I guess it's something similar to fields_for in Rails.
You could always look at the source for form_for / fields_for?

help a n00b understand rails, specifically inheritance, acts_as_nested_set, awesome_nested_set, sortable_element_for_nested_set

hey there, i'm trying to implement a drag and drop interface for a nested set in my first rails project. i'm new to rails so bear with me. my code is basically identical to this project: http://gist.github.com/128779. my problem is in the partial at this line:
<% for child in root.direct_children do %>
I'm getting a NoMethodError for direct_children which is an instance method of acts_as_nested_set, I believe. At the console if I try to create a new instance of my model, it is likewise unable to access the acts_as_nested_set instance methods, so I don't think the problem is in the partial but in the model.
Again, sorry if my terminology is wrong, I'm new to rails. Anyway, what am I doing wrong? I've got "acts_as_nested_set" in my model, just like the gist example above but my model does not appear to act as a nested set. How do I go about fixing this?
Thanks!
Here's the code for the model I am using (todo.rb):
class Todo < ActiveRecord::Base
acts_as_nested_set
end
And here's the partial:
<% content_tag :li, :id => dom_id(root) do %>
<%= content_tag :span, root.text %>
<% content_tag :ul do %>
<% for child in root.direct_children do %>
<%= render :partial => "tree", :locals => {:root => child}%>
<%end %>
<%end unless root.direct_children.empty? %>
<%end%>
root is passed to the partial from the view like:
<%= render :partial => "tree", :locals => {:root => #root} %>
and #root is defined in the controller like:
#root = Todo.find_by_parent_id(nil)
Again, the code is mostly copied wholesale with very few modifications from the gist link above.
A few things:
Have you checked that you installed the plugin properly? ./script/plugin install git://github.com/rails/acts_as_nested_set.git
Have you set up your table properly? Your model needs to have at least the following 3 columns by default (unless you want to override them): parent_id, lft, rgt. Without these acts_as_nested_set is going to have a hard time figuring out what's going on. I suggest you read the documentation at the top of this file because the readme doesn't say squat, nor does that gist for that matter.
If you've done the above, have you created a root element (not set the parent_id to anything) and then added at least one child to it?
m = Model.new
m.title = "My model's title"
m.save!
m2 = Model.new
m2.title = "My child"
m2.save!
m.add_child(m2)
I just did a quick test using the above, and afterwards I was able to do things like m.root? and m.direct_children. Good luck.
What I make from your title is that you're using quite a bit more than acts_as_nested_set. Try removing some plugins and try again.

Resources