Bootstrap collapse within table/between table rows not working - ruby-on-rails

I have a question regarding the Bootstrap collapse feature. I'm pretty sure that I'm overlooking something quite obvious or easy to fix, but I googled it alot and played with the code, but without success.
I have a "account settings" page, where all account information of a user is shown in a table-like format, with the table cells of the last table column always containing an "edit"-button to edit that information. When people click "edit", an edit form shall expand just beneath that table row.
I followed the scheme at http://twitter.github.com/bootstrap/javascript.html#collapse , the collapse function itself works fine, but the problem is that each form always expands above my table, regardless of which edit button I click on. I made a screenshot of how it looks like. http://imageshack.us/photo/my-images/834/problemyn.png/ Instead of being above the whole table I want it to expand just beneath the specific row, pushing the lower rows down.
Here my code:
<table class="table">
<tbody>
<tr>
<td>Username</td>
<td><%= #user.name %></td>
<td><button class="btn btn-danger" data-toggle="collapse" data-target="#username">Edit</button></td>
</tr>
<div id="username" class="collapse">
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |form| %>
<%= render 'shared/error_messages', object: form.object %>
<%= form.label :name, "Change Username" %>
<%= form.text_field :name %>
<%= form.submit "Save changes", class: "btn btn-primary" %>
<% end %>
</div>
</div>
</div>
<tr>
<td>Email</td>
<td><%= #user.email %></td>
<td><button class="btn btn-danger" data-toggle="collapse" data-target="#email">Edit</button></td>
</tr>
<div id="email" class="collapse">
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |form| %>
<%= render 'shared/error_messages', object: form.object %>
<%= form.label :email, "Change Email" %>
<%= form.text_field :email %>
<%= form.submit "Save changes", class: "btn btn-primary" %>
<% end %>
</div>
</div>
</div>
<tr>
<td>Password</td>
<td>Last time updated: <%= #user.updated_at %></td>
<td><button class="btn btn-danger" data-toggle="collapse" data-target="#password">Edit</button></td>
</tr>
<div id="password" class="collapse">
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |form| %>
<%= render 'shared/error_messages', object: form.object %>
<%= form.label :password, "Change Password" %>
<%= form.text_field :password %>
<%= form.label :password_confirmation, "Confirm Password" %>
<%= form.password_field :password_confirmation %>
<%= form.submit "Save changes", class: "btn btn-primary" %>
<% end %>
</div>
</div>
</div>
<tr>
<td>Language</td>
<td>English</td>
<td><button class="btn btn-danger" data-toggle="collapse" data-target="#language">Edit</button></td>
</tr>
<div id="language" class="collapse">
<div class="row">
<div class="span6 offset3">
<!-- code for language form -->
</div>
</div>
</div>
<tr>
<td>Avatar</td>
<td><%= avatar_status %></td>
<td><button class="btn btn-danger" data-toggle="collapse" data-target="#demo">Edit</button></td>
</tr>
<div id="demo" class="collapse">
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |form| %>
<%= form.label :avatar %>
<%= form.file_field :avatar %>
<%= form.submit "Add avatar", class: "btn btn-primary" %>
<% end %>
</div>
</div>
</div>
</tbody>
</table>

To collapse a table row, you should write extra css for the collapsed row:
table .collapse.in {
display: table-row !important;
}
It will fix the display issue after the row expanded.

Hi I'm sorry I won't have a satisfying answer. It is not allowed to have anything other than <tr> elements as descendants of <tbody> so your HTML is not valid. This is what causes the glitchy behavior. Your best bet is to wrap every part of your form in a new table element.

Related

Auto complete field on simple form with params

I have two models 'activity_templates' and 'activity'. I want to create a link on the activity_template index to create a new activity. I want to send activity_template params to the active form. I want to autocomplete the activity_template field on new activity form.
I can't figure out how to pass the params on the index page.
I think its a problem with the link.
Link:
<div class="box">
<div class="box-header">
<h3 class="box-title">Activities</h3>
</div>
<div class="box-body table-responsive no-padding">
<table class="table table-bordered">
<tbody>
<% #activity_templates.each do |activity_template| %>
<tr>
<td><%= activity_template.name %></td>
</tr>
<% end %>
</tbody>
</table>
<div class="text-right">
<%= will_paginate #activity_templates %>
</div>
</div>
</div>
URL:
http://localhost:3000/app/activities/new
Form:
<%= simple_form_for([:app, #activity]) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<div class="row">
<div class="col-md-6">
<%= f.association :resident, label_method: :full_name, prompt: "Choose a resident", collection: Resident.order(:first_name), selected: #resident.id %>
</div>
<div class="col-md-6">
<%= f.association :activity_template, collection: ActivityTemplate.order(:name).pluck(:name, :id), prompt: "Choose an activity template", selected: #activity_template.id %>
</div>
<div class="col-md-6">
<%= f.input :published_status, collection: ['Draft', 'Final'], default: 'Draft' %>
</div>
<div class="col-md-6">
<div class="form-group">
<label>Author</label>
<input class="form-control" type="text" placeholder="<%= #current_user.full_name %>" readonly value="<%= #activity.author.try(:full_name) %>">
</div>
</div>
</div>
<%= f.input :data %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Activity controller:
def new
#activity = current_business.activities.new
if params[:resident_id].present?
#resident = Resident.find(params[:resident_id])
end
if params[:activity_template_id].present?
#activity_template = ActivityTemplate.find(params[:activity_template_id])
end
end
I want to send activity_template params to the active form.
You should change #activity_template to activity_template in the link as you are iterating #activity_templates as activity_template.
<td><%= activity_template.name %></td>
Now you should see activity_template_id value in the url
http://localhost:3000/app/activities/new?activity_template_id=value
As you already capturing the params[activity_template_id] in the new, the rest should work now.
Also I recommend using link_to
<%= link_to activity_template.name, new_app_activity_path(activity_template_id: activity_template) %>

Nil:nil class error on each loop when Form to build object loaded on page first

I have a form on a page that is building a “tip” for a “guide”. Below the form, I am running an each loop over all the #guide.tips. I keep getting an error as the each loop is loading the forms blank object as it sees it as a tip. I’ve currently solved the problem by using jQuery to inject the form after page load, but there has to be a better solution.
Each Loop on Guide.html.erb
<% if !#guide.tips.blank? %>
<% #guide.tips.each do |tip| %>
<div class="row mx-1">
<div class="col-md-3 border-right">
<div class="float-left">
<%= image_tag avatar_url(tip.user), class: "float-left text-left align-middle rounded img-fluid mx-3", width: "30%" %>
<p><%= tip.user.fullname %></p>
</div>
<div class="float-right mr-3">
<%= link_to like_tip_path(tip), method: :put do %>
<div class="fas fa-angle-up"></div>
<%= tip.get_upvotes.size %>
<% end %><br/>
<%= link_to dislike_tip_path(tip), method: :put do %>
<div class="fas fa-angle-down"></div>
<%= tip.get_downvotes.size %>
<% end %>
</div>
</div>
<div class="col-md-8 ml-3">
<h6><%= tip.title %> -<span class="ml-1"><small><%= tip.created_at.strftime("%A, %d %b %Y %l:%M %p")%></small></span></h6>
<%= tip.tip %>
</div>
</div><hr/>
<% end %>
<% end %>
Tips_Controller.rb
def new
#guide = Guide.find(params[:guide_id])
#tip = Tip.new
end
def edit
end
def create
#guide = Guide.find(params[:guide_id])
params[:tip][:user_id] = current_user.id
#tip = #guide.tips.create!(tip_params)
redirect_to guide_path(#guide)
end
Tip Form Partial
<%= form_for([#guide, #guide.tips.build]) do |f| %>
<div class="form-group row">
<div class="col-sm-12">
<p class="text-left">Tip Title</p>
<%= f.text_field :title, placeholder: "Enter Title", class: "form-control" %>
</div>
<div class="col-sm-12 mt-2">
<p class="text-left">Your Tip</p>
<%= f.text_area :tip, placeholder:"What's your tip for this travel guide?", class: 'form-control' %>
</div>
</div>
<div class="form-group row">
<div class="col-md">
<%= f.submit 'Submit', class: 'btn btn-primary btn-block' %>
</div>
</div>
<% end %>
Here is another solution that does not separate the logic between the controller and the view and cleans up your empty array statement for your loop
Each Loop on Guide.html.erb
<% #guide.tips.each do |tip| %>
<div class="row mx-1">
<div class="col-md-3 border-right">
<div class="float-left">
<%= image_tag avatar_url(tip.user), class: "float-left text-left align-middle rounded img-fluid mx-3", width: "30%" %>
<p><%= tip.user.fullname %></p>
</div>
<div class="float-right mr-3">
<%= link_to like_tip_path(tip), method: :put do %>
<div class="fas fa-angle-up"></div>
<%= tip.get_upvotes.size %>
<% end %><br/>
<%= link_to dislike_tip_path(tip), method: :put do %>
<div class="fas fa-angle-down"></div>
<%= tip.get_downvotes.size %>
<% end %>
</div>
</div>
<div class="col-md-8 ml-3">
<h6><%= tip.title %> -<span class="ml-1"><small><%= tip.created_at.strftime("%A, %d %b %Y %l:%M %p")%></small></span></h6>
<%= tip.tip %>
</div>
</div><hr/>
<% end unless #guide.tips.blank? %>
Tip Form Partial
By creating the Tip from outside the association (i.e. not using build), it will not be loaded into the class variable's children
<%= form_for([#guide, Tip.new(guide: #guide)]) do |f| %>
<div class="form-group row">
<div class="col-sm-12">
<p class="text-left">Tip Title</p>
<%= f.text_field :title, placeholder: "Enter Title", class: "form-control" %>
</div>
<div class="col-sm-12 mt-2">
<p class="text-left">Your Tip</p>
<%= f.text_area :tip, placeholder:"What's your tip for this travel guide?", class: 'form-control' %>
</div>
</div>
<div class="form-group row">
<div class="col-md">
<%= f.submit 'Submit', class: 'btn btn-primary btn-block' %>
</div>
</div>
<% end %>
Another Example / Q&A
Using the structure you already have you could do:
<% if #guide.tips.count > 1 %> (assuming this will always be shown with an empty "build" tip)
or you can use:
<% next unless tip.persisted? %>
inside the loop, before the actual form.
You also don't need the blank? check as an .each on an empty enumerator simply won't execute the block, and as long as there's a has_many relationship between guide and tips it will always yield a collection proxy.
I would write it as:
<% #guide.tips.each do |tip| %>
<% next unless tip.persisted? %>
<div class="row mx-1">
<div class="col-md-3 border-right">
...
<% end %>

Lightbox with Rails

So I am trying to use Lightbox2 on my application. I installed the gem and followed all the steps, but having trouble figuring out where to call it in the application.
This is my post index
<div class="container">
<div id="profuploads">
<div id="posts" class="transitions-enabled">
<% #posts.each do |post| %>
<div class="box panel panel-default">
<%= link_to image_tag(post.image.url(:medium)), post %>
<div class="panel-body">
<strong><%= post.user.username if post.user %></strong><br/>
<%= post.description %>
<% if post.user == current_user %>
<div class="actions">
<%= link_to 'Edit', edit_post_path(post) %>
<%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
</div>
This is my post show
<div class="row">
<div class="col-md-offset-1 col-md-10">
<div class="panel panel-default">
<div class="panel-heading center">
<%= image_tag #post.image.url, height: '300' %>
</div>
<div class="panel-body">
<p><strong><%= link_to(#post.user.username.capitalize, user_path(#post.user.id)) if #post.user %></strong></p>
<p><%= #post.description %></p>
<div class="votes">
<strong>VIEWS</strong>
<%= #post.hits %>
<div class="votes">
<%= link_to like_post_path(#post), method: :put do%>
<button type="button" class="btn btn-info" aria-label="Left Align">
<span class="glyphicon glyphicon-thumbs-up glyphicon-align-center" aria-hidden="true"></span>
<span class="badge"><%= #post.get_upvotes.size %></span>
</button>
<%end%>
</div>
<% if #post.user == current_user %>
<%= link_to 'Edit', edit_post_path(#post) %>
<% end %>
</div>
</div>
</div>
</div>
With Lightbox do I need to just git rid of my post show page altogether?
Lightbox is a javascript library which needs proper html markup in order to do it's work. Your show view looks good except it does not include the markup Lightbox looks for.
From Lightbox Getting Started guide:
Add a data-lightbox attribute to any image link to enable Lightbox. For the value of the attribute, use a unique name for each image. For example:
Image #1
When Lightbox initializes, it looks for any image tags that contain data-lightbox attribute and hooks its handlers to them. You need to provide this attribute:
<%= image_tag #post.image.url, height: '300', "data-lightbox" => #post.image.url %>
This should make Lightbox pick up your images.

Can I update a user's attributes with a form in rails?

is there a way i can use a form to update a user's points in rails with a simple form that takes in the name and the points I want to append?
Heres the link to the app i made : enter link description here
my view for the index is :
<div class="container">
<h1 class="text-center">Listing Students</h1>
<div class ="jumbotron">
<table class="table table-hover">
<thead>
<tr>
<th>Name</th>
<th>Points</th>
</tr>
</thead>
<% #users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.points %></td>
<td><%= link_to 'Edit', edit_user_path(user) %></td>
<td><%= link_to 'Delete', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<br>
<%= link_to 'New Student', new_user_path, class:'btn btn-primary' %>
</div>
I tried using the code in my edit page :
<div class="container">
<div class=" text-center">
<div class="col-md-6 col-md-offset-3">
<div class= "well well-lg">
<%= render 'form' %>
<%= link_to 'Back', users_path, class:"back" %>
</div>
</div>
</div>
</div>
to render the form in the index but it gives me an error of #user can not be nill
I simply need to update the users points in the index page , it would be great if i can greate a modal to appear and then type in the name and edit it. Ive been working on this for hours and seem to update it .
Sure, you could use simple_form or form_for. Or you could do inplace editing. Your question is not very precise as to what exactly you need.
UPDATE 1:
Assuming that you have added simple_form gem to the gemfile, and that you have something like this in the routes.rb : resources :users, then edit view of the UsersController could look something like this:
#in controller
def edit
#user = User.find(params['id'])
end
And the view:
<%= simple_form_for #user do |f| %>
<%= f.input :name %>
<%= f.input :points %>
<%= f.button :submit %>
<% end %>
Please try it and let me know if it works for you (the edit view; in order to persist, you will need and update action as well).
Add a div on index page to open modal popup:
<div class='modal_popup>
</div>
For updating name and points of user on index page, you have to change edit link like this:
<%= link_to 'Edit', edit_user_path(user), remote: true %>
Controller changes:
def edit
#user = User.find(params[:id])
end
_modal.html.erb
<div class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">Modal title</h4>
</div>
<%= form_for #user, remote: true do |f| %>
<div class="modal-body">
<%= f.text_field :name %>
<%= f.text_field :points %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<%= f.submit 'Update', class: "btn btn-primary" %>
</div>
<% end %>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
edit.js.erb
$('.modal_popup').html("<%= j(render partial: '/users/modal') %>");
$('.modal').show();
After updating user in update.js.erb add below lines of code:
$('.modal').hide();
window.location.reload();
Hope this may help..

Rails: How should I adjust the 'each' method under a nest structure?

Before putting pinunder the nest structure of group,
One of the view looked like this:
<div class="transitions-enabled" id="pins">
<% #pins.each do |pin| %>
<div class="box panel panel-default">
<%= link_to (image_tag pin.image.url), pin %>
<div class="panel-body">
<h2><%= link_to pin.title, pin %></h2>
</div>
<div class="footer">
<div class="row footer-all">
<div class="col-md-6">
<p class="user">Submitted by <%= pin.user.username %></p>
</div>
<div class="col-md-6">
<div class="btn-group like_btn">
<% if user_signed_in? %>
<% if current_user.voted_up_on?(pin) %>
<%= link_to unlike_pin_path(pin), method: :put, class: "btn btn-default" do %>
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
<%end%>
<% else %>
<%= link_to like_pin_path(pin), method: :put, class: "btn btn-default" do %>
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
<%end%>
<% end %>
<% else %>
<div class="like_btn">
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
<%end%>
How should I adjust it after I put it under group (I'll mark the code which I think needed to change with'* *'):
Group has_many pins
Pin belongs_to group
<div class="transitions-enabled" id="pins">
<% #pins.each do |pin| %>
<div class="box panel panel-default">
<%= link_to (image_tag pin.image.url), *pin* %>
<div class="panel-body">
<h2><%= link_to pin.title, *pin* %></h2>
</div>
<div class="footer">
<div class="row footer-all">
<div class="col-md-6">
<p class="user">Submitted by <%= pin.user.username %></p>
</div>
<div class="col-md-6">
<div class="btn-group like_btn">
<% if user_signed_in? %>
<% if current_user.voted_up_on?(*pin*) %>
<%= link_to unlike_group_pin_path(*pin*), method: :put, class: "btn btn-default" do %>
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
<%end%>
<% else %>
<%= link_to like_group_pin_path(*pin*), method: :put, class: "btn btn-default" do %>
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
<%end%>
<% end %>
<% else %>
<div class="like_btn">
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
<%end%>
After stating that your objective is to use this view file to filter the pins depending on its group, then I can think of two approaches for this.
Use nested resources. (RailsCast)
This is a little trickier than 2. but it is much more organised, and RESTful
You could check the RailsCast if you are interested. Otherwise, I will just go explaining 2. as it's simpler.
Use params[:group_id] to filter the pins.
In the PinsController, add the following at the very end of the method where this view is rendered.
#group = Group.where(id: params[:group_id]).first
#pins = #pins.where(group: #group) if #group
Then in your view files, you'll just have to tweak your links to specify the group_id parameter. If this view file is associated to the #index method, then change
<%= link_to 'Link', pins_path %>
Into
<%= link_to 'Link', pins_path(group_id: 1) %>
Change 1 accordingly as you wish. If you don't specify the parameter group_id, the link will still work but you will notice that the page will show all pins, and not filtered by group.
Thanks for everyone's help, I think I find the problem:
The view should be changed into:
<div class="transitions-enabled" id="pins">
<% #pins.each do |pin| %>
<div class="box panel panel-default">
<%= link_to (image_tag pin.image.url), group_pin_path(#group, pin)
%>
<div class="panel-body">
<h2><%= link_to pin.title, group_pin_path(#group, pin) %></h2>
</div>
<div class="footer">
<div class="row footer-all">
<div class="col-md-6">
<p class="user">Submitted by <%= pin.user.username %></p>
</div>
<div class="col-md-6">
<div class="btn-group like_btn">
<% if user_signed_in? %>
<% if current_user.voted_up_on?(#group, pin) %>
<%= link_to unlike_group_pin_path(#group, pin), method: :put, class: "btn btn-default" do %>
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
<%end%>
<% else %>
<%= link_to like_group_pin_path(#group, pin), method: :put, class: "btn btn-default" do %>
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
<%end%>
<% end %>
<% else %>
<div class="like_btn">
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
<%end%>
And remember to state #group = Group.find(params[:group_id]) in the PinController, this is very important.

Resources