I have this code in the (ERB) view file:
<% if current_page?(some_object_path(some_object)) %>
<%= f.submit "Create Some Object", class:'btn btn-success'%>
<% else %>
<%= f.submit "Update Some Object", class:'btn btn-info'%>
<% end %>
and this:
<%= form_tag import_some_object_path, multipart: true do %>
<%= file_field_tag :file, class: "" %>
<%= submit_tag "Import CSV", class: "btn btn-info " %>
<% end %>
Now, the issue is that I have several of these different paths relating to respective classes (tables in the database). I don't want to replicate these codes in all 9 Class views in the app. Is there a way to refactor this so I can reference the code in just one location (say, a _partial), and then rails knows what object to insert in the some_object field depending on say, the current_page? Is there a magic wand way to do this?
(I have really scoured the internet but I can't find a solution. It may be that I am using the wrong search terms though)
Related
I have a Rails app that is running fine on Rails 3.x and ActiveAdmin 0.6.6. However I want to upgrade it to Rails 5 and ActiveAdmin 1.x. I started the upgrade process first upgrading from 3.x to 4.x and then to 5x, and with ActiveAdmin I tested with 1.0.0 and now I'm using the master from Github.
Everything worked fine with the App in both Rails versions and ActiveAdmin but the ActiveAdmin forms that are in a partial.
The problem is the following:
I have a file app/admin/menu.rb whose has a partial views/admin/menus/_form.html.erb.
The partial contains the form of the Menu.
This is the contents of the partial (views/admin/menus/_form.html.erb):
<%= semantic_form_for [:admin, #menu], builder: ActiveAdmin::FormBuilder do |f| %>
<% f.inputs 'Campos Menu' do %>
<% f.input :project if current_admin_user.admin? %>
<% f.input :title %>
<% f.input :title_en %>
<% f.input :item %>
<% f.input :icon, as: :file %>
<% end %>
<% f.inputs 'Submenus' do %>
<% f.has_many :submenus, heading: '' do |fa| %>
<% fa.input :title, as: :string %>
<% fa.input :title_en, as: :string %>
<% fa.input :kind, as: :select, collection: Submenu.kind_collection %>
<% fa.input :items_as, as: :select, collection: Submenu.items_as_collection %>
<% end %>
<% end %>
<% f.actions do %>
<% f.action :submit %>
<% end %>
<% end %>
The render result of this file is only the 'actions' buttons, in this case the 'submit' button. The interesting thing is that if I remove the <% f.actions do %>... from the partial then the <% f.inputs 'Submenus' do %> gets rendered and the same if I remove the later. In other others is being rendered on the last block that contains an end.
The same behaviour is being observed on Rails 4.x and 5.x (except Rails 5.1.x which I didn't tested).
If I move the form from the partial to the app/admin/menu.rb it gets rendered properly. This could be a solution for me however I have others forms that make use of JQuery for fields manipulation and other stuff on the front end.
As I said before, all these forms partials were working properly on Rails 3.x and ActiveAdmin 0.6.6.
Anyone knows what's the problem?
DISCLAIMER: I'm not a Rails or ActiveAdmin expert, so bear with me if is a silly mistake related to this issue.
Yes, it's activeadmin#3486 I'm glad you figured out the workaround. I'm curious if this Arbre branch fixes it for you. Glad to see people still upgrading, I'll do what I can to help.
The solution that I found was to put a = for the <% f.input(s) %> on the partial. Having something like this <%= f.inputs ... %> instead of this <% f.inputs ... %> solves the problem.
I am taking a rails class at my University and I am trying to create a search form which will show the results on the same page rather than show a different page of results. Is this something simple to do? I am creating a museum app with artifacts for each museum but I want the user to search artifacts from either page.
On my routes.rb I have
resources :artifacts do
collection do
get 'search'
end
end
On my museum index I have the code below that he gave us but not sure how to tweak the get routes for the same page.
<%= form_tag search_artifacts_path, :method => 'get' do %>
<p>
<%= text_field_tag :search_text, params[:search_text] %>
<%= submit_tag 'Search' %>
</p>
<% end %>
<% if #artifacts %>
<p> <%= #artifacts.length %> matching artifacts. </p>
<h2> Matching Artifacts </h2>
<% #artifacts.each do |a| %>
<%= link_to "#{a.name} (#{a.year})", a %><br />
<% end %>
<% end %>
Yes, this is easy. Just have the index page return the search results if params[:search_text] is present - this way you don't need a new route or a different page.
class ArtifactsController < ApplicationController
def index
#artifacts = Artifact.search(params[:search_text])
end
end
class Artifact < ActiveRecord::Base
def self.search(query)
if query
where('name ILIKE ?', "%#{query}%")
else
all
end
end
end
So then your form looks like:
<%= form_tag artifacts_path, :method => 'get' do %>
<p>
<%= text_field_tag :search_text, params[:search_text] %>
<%= submit_tag 'Search' %>
</p>
<% end %>
Edit:
So what you really want to do is any page you want to search, include a form which makes a request to that same page.
Then in each of those controller methods just put this line of code:
#artifacts = Artifact.search(params[:search_text])
and that will populate the #artifcats array with only artifacts that match the search query.
Try using "Ransack" gem. It can also perform some more powerful searches.
Let's say I have a schema in which an apple crate contains zero or more apples. While editing the apple crate in a form, I want to list the apples and provide a checkbox next to each apple, for deleting it when the form is submitted.
There is nothing going wrong that I can see. In my model I say
class AppleCrate < ActiveRecord::Base
has_many :apples
accepts_nested_attributes_for :apples, :allow_destroy => true
...
end
I have the form working, so far as I can tell. The checkboxes appear in the form html and when the form is processed by the controller each apple in the list has an attribute called "_destroy" which is set to either "1" or "0" depending on whether or not I checked the box before submitting.
According to the Rails API, when I set _destroy to 1 and save, the apple should be deleted. But when I submit the form I get
ActiveRecord::UnknownAttributeError in AppleCrateController#update
unknown attribute: _destroy
...
"apple_crate"=>{"id"=>"10101", "apples"=>{"1"=>{"id"=>"1",
"variety"=>"granny smith",
"apple_crate_id"=>"10101",
"_destroy"=>"1"},
"2"=>{"id"=>"2",
"variety"=>"fuji",
"apple_crate_id"=>"10101",
"_destroy"=>"1"},
"3"=>{"id"=>"3",
"variety"=>"macintosh",
"apple_crate_id"=>"10101",
"_destroy"=>"0"},
...
and so on.
I must be missing something obvious but after several days of futzing around I can't figure it out. I can successfully do everything else -- update, edit, index, etc -- so long as I leave out the :_destroy attribute. Any ideas?
(For what it's worth, I'm running rails 3.2.2 on Windows.)
Updated:
This is what I'm looking at in the documentation. (See the subsection "One-to-many".)
Updated:
As requested in comments, here is the view:
<%= form_for #apple_crate do |f| %>
<% #apples = #apple_crate.apples %>
<% #apples.each do |apple| %>
<%= fields_for "apples[]", apple do |apple_fields| %>
<%= apple_fields.text_field :variety %>
<%= apple_fields.hidden_field :apple_crate_id %>
<%= apple_fields.hidden_field :id %>
<%= apple_fields.check_box :_destroy %>
<% end %>
<% end %>
<%= f.submit "Save" %>
<% end %>
You should generate nested forms and forms with rails helpers, don't do it by your hands. So I think that's where your error at.
Try:
<%= form_for #apple_crate do |f| %>
<%= f.fields_for :apples do |apple_fields| %>
<%= apple_fields.text_field :variety %>
<%= apple_fields.hidden_field :apple_crate_id %>
<%= apple_fields.hidden_field :id %>
<%= apple_fields.check_box :_destroy %>
<% end %>
<% end %>
something like this, did not check if it's correct, but idea should be clear enough
I'm editing multiple instances of a parent model in an index view in one form, as in Railscasts #198.
Each parent has_many :children and accepts_nested_attributes_for :children, as in Railscasts #196 and #197
<%= form_tag %>
<% for parent in #parents %>
<%= fields_for "parents[]", parent do |f|
<%= f.text_field :job %>
<%= f.fields_for :children do |cf| %>
<% cf.text_field :chore %>
<% end %>
<% end %>
<% end %>
<% end %>
Given parent.id==1
f.text_field :job correctly generates
<input id="parents_1_job" type="text" value="coding" size="30" name="parents[1][job]">
But cf.text_field :chore generates ids and names that don't have the parent index.
id="parents_children_attributes_0_chore"
name="parents[children_attributes][0][chore]"
If I try passing the specific child object to f.fields_for like this:
<% for child in parent.children %>
<%= f.fields_for :children, child do |cf| %>
<%= cf.text_field :chore %>
<% end %>
<% end %>
I get the same. If I change the method from :children to "[]children" I get
id="parents_1___children_chore"
which gets the right parent_index but doesn't provide an array slot for the child index.
"[]children[]" isn't right either:
id="parents_1__children_3_chore"
as I was expecting attributes_0_chore instead of 3_chore.
Do I need to directly modify an attribute of the FormBuilder object, or subclass FormBuilder to make this work, or is there a syntax that fits this situation?
Thanks for any thoughts.
I did solve this problem by reading the source code for FormBuilder.fields_for
One possible answer: Yes, modify the f.object_name attribute of the FormBuilder object.
Specifically in this situation
f.fields_for :children
is going to call
f.fields_for_with_nested_attributes
which sets the name variable based on f.object_name. The id for the generated element looks like it is based on the name,so both match in the resulting html.
def fields_for_with_nested_attributes(association_name, args, block)
name = "#{object_name}[#{association_name}_attributes]"
.....
So one way to tell f.fields_for to do what I wanted is to set f.object_name to include the parent id for the duration of the f.fields_for block
<% old_object_name = f.object_name %>
<% f.object_name="parents[#{f.object.id}]" %>
<% =f.fields_for :children do |cf| %>
<%= cf.text_field :chore %>
<% end %>
<% f.object_name=old_object_name #should be "parents[]" %>
Then everything within the f.fields_for block can use the standard rails helpers unmodified.
I wrote a form that generates a text input for each property.
The list of properties is configurable by the customer.
<% properties = ["refractivity_at_2kHz", "refractivity_at_5kHz"] %>
<% properties.each do |property| %>
<div class="property">
<%= f.label property %>
<%= f.text_field property %>
</div>
<% end %>
It fails with the error undefined method refractivity_at_2kHz.
What is the usual solution for this problem?
Should I add an array to my model, and use f.text_field myarray[property] ?
Is it a form_for(#model)?
Because then f.text_field(property) looks for that method/property on #model.
May be you want to change f.text_field(property) into text_field_tag(property)[1]
cheers
[1] http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-text_field_tag