I have a model called Offer and another called PurchasinGroup
Offer has many PurchasingGroups
Offer accepts nested attributes for PurchasingGroups
While creating an offer you can add as many PurchasingGroups as you want.
PurchasingGroup has a boolean attribute called active.
while editing an Offer you can see all the created PurchasingGroups, however I want to let the user edit only the PurchasingGroups that are active, and do not display the inactive purchasing groups.
This is my edit action in offers_controller.rb:
def edit
#offer = Offer.find(params[:id])
end
And this is my form (only the part that matters):
<fieldset>
<legend>Purchasing groups</legend>
<%= f.fields_for :purchasing_groups do |builder| %>
<%= render partial: 'purchasing_group_fields', locals: { f: builder } %>
<% end %>
</fieldset>
In the edit form all the purchasing groups are being shown for edit, I want to show only those that are active I mean purchasing_group.active == true
How is the best way to do it?
<%= f.fields_for :purchasing_groups, #offer.purchasing_groups.where(active: true) do |builder| %>
<%= render partial: 'purchasing_group_fields', locals: { f: builder } %>
<% end %>
on the other hand, you can also add a association in your model
class Offer
has_many :active_purchasing_groups, class_name: "PurchasinGroup", -> { where(active:true) }
...
end
and then
<%= f.fields_for :active_purchasing_groups do |builder| %>
<%= render partial: 'purchasing_group_fields', locals: { f: builder } %>
<% end %>
Related
I have the following code
<%= form_tag('/update', method: :post) do %>
<%= select_tag :role, UserSomething.roles.keys.map {|role| [role.titleize,role]} %>
Role is an enum which text values have to be displayed in the drop down menu, and on form submit, i have to send the index of selected enum to some controller. I don't know how to set select_tag propertly.
I would use the helper options_for_select to map the array you get from UserSomething.roles.keys.map to a list of options for the select. I don't think out the select_tag method handles an array of the box, it needs a list of option tags. See the docs here.
<%= form_tag('/update', method: :post) do %>
<%= select_tag :role, options_for_select(UserSomething.roles.keys.map {|role| [role.titleize,role]}) %>
<% end %>
I am trying to implement the acts_as_taggable_on gem. In my set up I have a Model called Discipline which is pre-populated with about 40 names.
I also have a Model Micropost which I want to tag - using a select box containing all the names in the disciplines database. I thought that I could call the acts_as_taggable_on the Model I wanted - in this case Disciplines but its not working with my current set up.
class Micropost < ActiveRecord::Base
acts_as_taggable
acts_as_taggable_on :disciplines
end
Here is the form......
<%= simple_form_for(#micropost) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.input :tag_list, :as => :select,
:multiple => :true,
:collection => ActsAsTaggableOn::Tag.pluck(:name) %>
<%= f.text_area :content, placeholder: "What is your question?", :style => "height:75px;" %>
<%= f.submit "Post", class: "btn btn-primary" %>
<% end %>
I can tell from the documentation that there is a way to do this....but I guess I am just not getting it. Any suggestions?
I don't think you can use acts_as_taggable_on using a model other than the default Tag and Taggings models.
Alternative Approach #1
Seed your database with the pre-populated 40 Tags containing your discipline names.
Alternative Approach #2
Use bitmask_attributes for your 40 disciplines.
For example, in my application I have:
bitmask :instruments, as: [:others, :guitar, :piano, :bass, :mandolin, :banjo,
:ukulele, :violin, :flute, :harmonica, :trombone,
:trumpet, :clarinet, :saxophone, :viola, :oboe,
:cello, :bassoon, :organ, :harp, :accordion, :lute,
:tuba, :ocarina], null: false
I'm using form for and the name of the form in the controller is appearing as "#", but I expect it to appear as :edge.
Here's my controller:
def new
#some_stuff
#edge = Edge.new
#some_stuff
end
def create
#edge = Edge.new(edge_params)
#edge.save
end
def edge_params
params.require(:edge).permit(:location_1_id, :location_2_id)
end
View:
<%= form_for( :edge, :url => {:action => 'create'}) do |f| %>
<ul>
<li>
<%= f.label :location_1_id %>
<%= collection_select(#edge, :location_1_id, #location, :id, :record_as_string) %>
</li>
<%= submit_tag(t(:create_edge)) %>
</ul>
<% end %>
Param req:
{"utf8"=>"✓", "authenticity_token"=>"blah",
"#"=>{"location_1_id"=>"91", "location_2_id"=>"92"},
"commit"=>"Create Edge", "action"=>"create",
"controller"=>"admin/edges", "floor_map_floor_id"=>"1"}
So the name of the parameter should be :edge but it's an object that I can't access.
Can anybody tell me what I'm missing?
Any help is appreciated.
You should be using the form block on your collection set like so
<%= f.collection_select(:location_1_id, #location, :id, :record_as_string) %>
(notice that you are calling the collection_select on the block variable f, and NOT passing in the #edge as the first argument).
In addition, because you are creating the object in new (#edge = Edge.new), you should just be using in your form, like so
<%= form_for( #edge, :url => {:action => 'create'}) do |f| %>
(although using :edge wasn't the cause of your problems, I suspect it was because you were using :edge and #edge in the same form. You need to be consistent, use one or the other)
In my current solution, I am able to put a checkbox in the edit form so that users can delete attachment. However, there is no indication for the user that a file has been uploaded, the name of that file, etc. so that he can decide whether to delete.
Right now the form look like this. The first material is an existing one, the next 3 are due to
def edit
#post = Post.find(params[:id])
3.times { #post.post_materials.new }
end
As you can see, it's very hard to distinguish between them. Ideally, I want the first material file name to appear somehow.
<%= form_for #post, :html => { :multipart => true } do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
Materials:
<ul>
<%= f.fields_for :materials, :html => { :multipart => true } do |materials_form| %>
<li>
<%= materials_form.label :asset %>
<%= materials_form.file_field :asset %>
<%= materials_form.label :_destroy, class: "checkbox inline" do %>
Remove attachment <%= materials_form.check_box :_destroy %>
<% end %>
</li>
<% end %>
</ul>
<%= f.submit "Submit", class: "btn btn-large" %>
<% end %>
Running paperclip's generator creates a migration to add 4 attributes on your model, as you can see here. These attributes are:
<attachment>_file_name
<attachment>_file_size
<attachment>_content_type
<attachment>_updated_at
So, If you ran the generator this way: rails generate paperclip post_material asset, on your PostMaterial model, you will have these attributes:
asset_file_name
asset_file_size
asset_content_type
asset_updated_at
Then, on your code you can do something like this:
if materials_form.object.asset.exists? #object represents the current post_material instance
#show a label with object.asset_file_name
else
#render materials_form.file_field :asset
end
If Project has_many Genre through: GenresProject
and params are:
def project_params
params.fetch(:project, {}).permit(genres_projects_attributes: [:id, {genre_id: []})
end
and my submit form is:
<%= form_for #project do |f| %>
<%= f.fields_for :genres_projects_attributes do |ff| %>
<%= ff.select :genre_id, Genre.order(:id).collect{|g| [g.name, g.id]}, {}, { multiple: true } %>
<% end %>
<%= f.submit 'Update'%>
<% end %>
and my params look like this:
"project"=>{ ... "genres_projects_attributes"=>{"genre_id"=>["3", "5"]}} ... }
Should
project.update(project_params)
Automatically iterate through the genre_id array and create the appropriate GenresProject records?
If you don't have GenreProject record, then you will not get an id from the params.
Secondly, it will not automatically create the new Genre record or update one for you, I think. You should handle creating new record in the update action yourself. For example:
params[:project][:genre_id].each do |id|
unless GenreProject.find(id)
# create new record here
GenreProject.create
end
# other updating operations
end
Hope it works for you