I have Article(s), that has_many ArticleAssets. Fairly simple. On the edit form for the Article I just want to add new article assets. I don't need to edit the current ones, so I created a partial like this:
<% f.fields_for :article_assets, article_asset do |builder| -%>
<div class="article_asset">
<%= builder.file_field :image %>
<%= builder.check_box :is_flagged, :class => "isFlagged" %> isFlagged
</div>
<% end -%>
No collection, because I only need one object at a time and need no data from the existing article assets. In the form of edit.erb I render the following:
<%= render :partial => 'article_asset', :locals => {:f => f}, :object => ArticleAsset.new %>
This makes one new article asset show up that I can add information to, all cool so far. Important is that this field gets the name-form of article[article_assets_attributes][0][is_flagged]. All good since this will also group the hidden field that always comes with a checkbox in rails to the rest of the fields. Then I have an "Add item" link that does this:
page.insert_html :bottom, :article_assets_fields, :partial => "article_asset", :locals => {:f => f}, :object => ArticleAsset.new
Clicking on this link gives a new field under the created one, as expected, with the name-form of the checkbox field of article[article_assets_attributes][1][is_flagged]. Incremented, that's perfect! Adding another one with the same link however, also gives the same form (also with the identifier of 1, duplicate), which makes submitting the form only have 2 items instead of 3. Does anyone know why this happens and what I can do to solve it?
Ruby on Rails 2.3.11
Nested form 2.3 fail. This one was the bane of my existence for some time, even having watched the railscast etc. Here's my how to:
1) this goes in article.rb
after_update :save_article_assets
def new_article_asset_attributes=(article_asset_attributes)
article_asset_attributes.each do |attributes|
article_assets.build(attributes)
end
end
def existing_article_asset_attributes=(article_asset_attributes)
article_assets.reject(&:new_record?).each do |article_asset|
attributes = article_asset_attributes[article_asset.id.to_s]
if attributes
article_asset.attributes = attributes
else
article_assets.delete(article_asset)
end
end
end
def save_article_assets
article_assets.each do |article_asset|
article_asset.save(false)
end
end
2) In a helper somewhere:
def add_article_asset_link(name)
button_to_function name, :class => "new_green_btn" do |page|
page.insert_html :bottom, :article_assets, :partial => "article_asset", :object => ArticleAsset.new()
end
end
def fields_for_article_asset(article_asset, &block)
prefix = article_asset.new_record? ? 'new' : 'existing'
fields_for("article[#{prefix}_article_asset_attributes][]", article_asset, &block)
end
3) in your partial:
<% fields_for_article_asset(article_asset) do |aa| %>
<tr class="article_asset">
<td><%= aa.text_field :foo %></td>
<td><%= link_to_function "remove", "$(this).up('.article_asset').remove()" %></td>
</tr>
<% end %>
4) in the _form:
<table>
<%= render :partial => "article_asset", :collection => #article.article_assets %>
</table>
<%= add_article_asset_link "Add asset" %>
Related
I'm having a little trouble with using AJAX on something I've done before with no issues, but this site has a few different configurations which are causing trouble for me. The main problem I'm having, is when I click the Like link on a post, all of the like links on that page are changed to unlike, even though the one I clicked is the only one getting posted in the Database.
On my user's profile page (users/show.html.erb), I'm showing all of the posts (updates in this scenario) that the particular user has posted.
Here is my configuration thus far:
Users Controller, Show Action
def show
#updates = #user.updates.paginate(:page => params[:page], :per_page => 20)
end
Updates Controller, Like Action
def like
begin
#vote = current_user.vote_for(#update = Update.find(params[:id]))
if #vote.save
respond_with #update.user, :location => profile_path(#update.user)
end
rescue ActiveRecord::RecordInvalid
redirect_to #update
end
end
users/show.html.erb
<div class="like_button">
<%= render :partial => 'updates/like_button', :locals => {:update => update} %>
</div>
updates/_like_button.html.erb Partial
<% if current_user.voted_on?(update) %>
<%= link_to unlike_update_path(update), :method => :post, :remote => true do %>
<i class="ss-heart liked" title="Unlike Update"></i>
<% end %>
<% else %>
<%= link_to like_update_path(update), :method => :post, :remote => true do %>
<i class="ss-heart animate" title="Like Update"></i>
<% end %>
<% end %>
updates/like.js.coffee
$(".like_button").html("<%= escape_javascript render :partial => 'updates/like_button', :locals => {:update => #update} %>");
So just to refresh, the like button works and records the vote into the database, but it changes all of the like_buttons on the page to appear as if they have been liked instead of just the one post.
You need some way to distinguish your like buttons (by css class / id for example) and then you can alter them with jQuery concretely
$(".like_button").html("<%= escape_javas...
while currently $(".like_button") aims for all elements with that .like_button class (which are all).
I've got a Rails application that is using nested forms. Details follow and I tried this solution (Rails 3 Nested Models unknown attribute Error), but for some reason, the field is repeating multiple times instead of listing and saving the options correctly. Thanks in advance for your help!
Model information for Newsavedmaps
has_many :waypoints, :dependent => :destroy
accepts_nested_attributes_for :waypoints
Newsavedmap_controller
def new
#newsavedmap = Newsavedmap.new
waypoint = #newsavedmap.waypoints.build
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #newsavedmap }
end
end
def edit
#newsavedmap = Newsavedmap.find(params[:id])
if #newsavedmap.itinerary.user_id == current_user.id
respond_to do |format|
format.html # edit.html.erb
format.xml { render :xml => #activity }
end
else
redirect_to '/'
end
end
Maptry View
<% form_for #newsavedmap, :html=>{:id=>'createaMap'} do |f| %>
<%= f.error_messages %>
<% f.fields_for :waypoint do |w| %>
<%= w.select :waypointaddress, options_for_select(Waypoint.find(:all, :conditions => {:newsavedmap_id => params[:newsavedmap_id]}).collect {|wp| [wp.waypointaddress, wp.waypointaddress] }), {:include_blank => true}, {:multiple => true, :class => "mobile-waypoints-remove", :id =>"waypoints"} %>
<% end %>
<% end %>
When I use the above code, my form works correctly, but submitting it gives me this error:
UnknownAttributeError (unknown attribute: waypoint)
When I change ":waypoint do |w|" to ":waypoints do |w|" in the view, the select field disappears when the user is creating a new record, and in the edit view, the select field appears several times (however many waypoints the user saved in the record.)
How can I get this form field to work properly?
EDIT 1
Here is my latest attempt. For new records, the select field does not appear. However, in the edit view, the select field appears multiple times. This is a Rails 2 application, FYI. Taking a cue from the comments, I used a collection_select approach (not collection_for_select because I couldn't find documentation for that.) Again, I appreciate your help!
<% f.fields_for :waypoints do |w| %>
<%= w.collection_select( :waypointaddress, #newsavedmap.waypoints, :waypointaddress, :waypointaddress, {:include_blank => true}, {:id =>"waypoints"} ) %>
<% end %>
Your form has the following problems.
Use f.fields_for :waypoints since the argument needs to match the name of the association.
Use collection_select rather than select, since you have an ActiveRecord model behind that field.
So, taking that into account, you could try this for your form:
<% form_for #newsavedmap, :html => { :id => 'createaMap' } do |f| %>
<%= f.error_messages %>
<% f.fields_for :waypoints do |w| %>
<%= w.collection_for_select :waypoint, :waypointaddress, #newsavedmap.waypoints, :waypointaddress, :waypointaddress, { :include_blank => true }, { :multiple => true, :class => "mobile-waypoints-remove", :id =>"waypoints" } %>
<% end %>
<% end %>
The API for collection_select is a bit tricky to get right. I usually need a few attempts as well. This previous SO question may help clear things up: Can someone explain collection_select to me in clear, simple terms?
Believe you can help me.
I'm trying to add new functionality to legacy code (Typo). But it seems that there is some problem about routing.
In the project routes are generated the following way:
%w{advanced cache categories comments content profiles feedback general pages
resources sidebar textfilters themes trackbacks users settings tags redirects seo post_types }.each do |i|
match "/admin/#{i}", :to => "admin/#{i}#index", :format => false
match "/admin/#{i}(/:action(/:id))", :to => "admin/#{i}", :action => nil, :id => nil, :format => false
end
My functionality is about merging articles. For that I've added new action in the /admin/content controller:
def merge
#some code here
end
A piece of a view partial (_form.html.erb) added by me:
<% if current_user.admin? and !#article.id.nil?%>
<div class=''>
<h4><%= _("Merge Articles") %></h4>
<%= label_tag :merge_with, 'Article ID' %><%= text_field_tag :merge_with, nil, :size => 20 %>
<%= button_to 'Merge', admin_content_merge_path(:id => #article.id) %>
</div>
<%end%>
This partial is rendered by another partial (_edit.html.erb)
<%= form_tag(form_action, :id => "#{form_type}_form", :enctype => "multipart/form-data", :class => className) do %>
<%= render :partial => "form" %>
<% end %>
And finally _edit.html.erb is rendered by view new.html.erb
<%= render "admin/shared/edit", { :form_type => "article", :form_action => { :action => "new", :id => #article.id , :class => ('autosave')} } %>
The problem is how to write a correct route for the controller action above which will allow me to render an edit page containing newly merged article. I wrote:
match "/admin/content/merge/:id" => "admin/content#merge",:as => 'admin/content/merge'
rake routes output:
admin_content_merge /admin/content/merge/:id(.:format) {:controller=>"admin/content", :action=>"merge"}
But the new or edit action is being invoked as I can see.
Apparently, my route is wrong, isn't it?
Could you please help me with this.
Thanks in advance!
Update
Up-to-date new.html.erb:
<% #page_heading = _('New article') %>
<%= render "admin/shared/edit", { :form_type => "article", :form_action => { :action => "new", :id => #article.id , :class => ('autosave')} } %>
<% if current_user.admin? and !#article.id.nil?%>
<%= form_tag "/admin/content/merge/#{#article.id}" do %>
<h4><%= _("Merge Articles") %></h4>
<%= label_tag :merge_with, 'Article ID' %>:
<%= text_field_tag :merge_with %><br />
<%= submit_tag "Merge" %>
<% end %>
<% end %>
Read the hint from the course:
HINT:Nesting is invalid in HTML.
That means that you can't nest form tags, don't put the form tag in another form tag, your nested form wont be able to do a correct action.
Since you have to put your code at the end of the page, try and see how to do it with having your merging form tag below the main edit article form tag. So basically you can find where the big form tag ends and put it below it.
Try to see if you can figure it out, and if not, don't hesitate to ask :)
Btw. I think everybody had some problem with this
I'm trying to observe a field that get generated inside a fields_for loop.
The thing is that the id of that field is generated dynamically.
_form.html.erb
<% form_for #exp, :url => {:action => "update"} do |f| %>
<% f.fields_for:patterns do |builder| %>
<%= render 'pattern_fields', :f => builder %>
<% end %>
<% end %>
_pattern_fields.html.erb
Pattern: <%= f.select(:LC_PATTERN, [['stripes', 'stripes'],
['dots', 'dots'],
['lines', 'lines'],
],{ :prompt => "Please select"}
) %>
<%= observe_field("------", :frequency => 1,
:with => "'id='+value", :function => 'alert(value)')%>
My question is how do i get the id of the field inside the fields_for tag.
I finally got it. Found this solution on the internet...Hope it might be of help to someone else.
In your application_helper.rb, add the following functions:
def sanitized_object_name(object_name)
object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/,"_").sub(/_$/,"")
end
def sanitized_method_name(method_name)
method_name.sub(/\?$/, "")
end
def form_tag_id(object_name, method_name)
"#{sanitized_object_name(object_name.to_s)}_#{sanitized_method_name(method_name.to_s)}"
end
You can then view the id of the fields generated inside 'fields_for' by using the following code:
<%=form_tag_id(f.object_name, :LC_PATTERN) %>
I am trying to create a tabbed interface using the prototype helper method "replace_html." I have three different partials I am working with. The first one is the 'main tab' and it is loaded automatically like so:
<div id = "grid">
<% things_today = things.find_things_today %>
<%= render :partial => "/todaything", :collection => things_today, :as =>:thing %>
</div>
...which works fine. Similarly, I have a _tomorrowthing partial which would replace the content in the 'grid' div like so:
<%things_tomorrow = things.find_things_tomorrow%>
<%= link_to_function('Tomorrow',nil, :id=>'tab') do |page|
page.replace_html 'grid' , :partial => '/tomorrowthing',:collection => things_tomorrow, :as => :thing
end %>
If I click on this tab nothing happens at all. Using firebug, the only errors I find are a missing ) after argument list which is contained in the Element.update block where the link_to_function is called. What am I doing wrong?
Hey Jack i try to reproduce the same but i can't i never used link_to_function before but
Following code may help to achieve the same you want
<%= link_to_remote "Today Thing", :url=>{:action=>"things", :id=>'today'}%>
<%= link_to_remote "Tomorrow Thing", :url=>{:action=>"things", :id=>'tomorrow'}%>
<div id = "grid">
<% #things = things.find_things_today %>
<%= render :partial => "/todaything", :collection => #things %>
</div>
in controller
def things
#things= (params[:id]=="today")? things.find_things_today : things.find_things_tomorrow
render :update do |page|
page.replace_html 'grid', :partial => (params[:id]=="today")? "/todaything" : '/tomorrowthing' , :objects=> #things
end