I am trying to implement a contact form on my one-paged portfolio site using the mail_form gem and cannot seem to get the form to show up when using AJAX. I resorted to AJAX in place of the redirect_to approach because I do not want the site to refresh and scroll down to the anchor upon submission.
views/pages/home.html.erb:
<%= render 'contacts/new' %>
<div id="contact_form"></div>
config/routes.rb:
Rails.application.routes.draw do
root 'pages#home'
resources :contacts, only: [:new, :create]
end
models/contact.rb:
class Contact < MailForm::Base
attribute :name, validate: true
attribute :email, validate: /\A([\w\.%\+\-]+)#([\w\-]+\.)+([\w]{2,})\z/i
attribute :message, validate: true
attribute :nickname, captcha: true
def headers
{
subject: "Regarding Your Portfolio",
to: "email (removed for privacy)",
from: %("#{name}" <#{email}>)
}
end
end
controllers/contacts_controller.rb:
class ContactsController < ApplicationController
before_action :contact_params, only: [:new, :create]
def new
#contact = Contact.new
end
def create
#contact = Contact.new(params[:contact])
#contact.request = request
if #contact.deliver
respond_to do |format|
# format.html {redirect_to root_path(anchor: "contact"), notice: 'Thank you for your message! I will get back to you shortly.'}
format.html {flash.now[:notice] = 'Thank you for your message! I will get back to you shortly.'}
format.js {render partial: 'contacts/new'}
end
else
respond_to do |format|
format.html {flash.now[:alert] = 'Your message could not be sent. Please try again.'}
format.js {}
end
end
end
private
def contact_params
params.require(:contact).permit(:name, :email, :message, :nickname, :captcha)
end
end
controllers/pages_controller:
class PagesController < ApplicationController
def home
#contact = Contact.new
end
end
contacts/_new.js.erb:
document.querySelector('#contact_form').innerHTML = '<%= j render 'new', locals: {contact: #contact} %>'
contacts/_new.html.erb:
<div class="row">
<div class="mb-md-0 mb-5">
<%= form_for #contact, id: 'contact_form', remote: true do |f| %>
<div class="row">
<div class="col-2"></div>
<div class="col-md-4">
<div class="md-form mb-0">
<%= f.text_field :name, required: true, class: 'form-control', placeholder: "Name" %>
</div>
</div>
<div class="col-md-4">
<div class="md-form mb-0">
<%= f.text_field :email, required: true, class: 'form-control', placeholder: "Email" %>
</div>
</div>
</div>
<div class="row">
<div class="col-2"></div>
<div class="col-md-8">
<div class="md-form mt-4">
<%= f.text_area :message, rows: 8, required: true, class: 'form-control md-textarea', placeholder: "Message"%>
</div>
</div>
</div>
<div class= "hidden d-none">
<%= f.text_field :nickname %>
</div>
<div class="text-center text-md-left">
<%= f.submit 'Send Message', class: 'btn btn-outline-secondary btn-sm col-3 mt-4 mx-auto' %>
</div>
<% end %>
</div>
</div>
The form works, but I would love to figure out why AJAX isn't working for it. I have searched for many hours and have also copied code from a previous application of mine that uses AJAX for a form to no avail. I want to be able to have the same effect as redirect_to root_path without having to reload the page and auto-scroll to the anchor. I have also tried copying the create method from the contacts_controller to the pages_controller with no success either. Any tips would be greatly appreciated!
I am venturing into AJAX and would like to delete a record of a model and followed this thread : How to perform Controller.destroy action asynchronously in rails?
models:
Photographe
Photographephoto
views/photographes/edit.html.erb
<div id="sectionimages" class="gutter-0 row" >
<% #photographe.photographephotos.all.each do |f| %>
<div class="col-md-2 col-sm-3 col-xs-6 col">
<%= link_to professionnel_photographe_photographephoto_path(#photographe.professionnel.id,#photographe.id, f.id), method: :delete, remote: 'true', id: "destruction"+f.id.to_s do %>
<div class="killimage" >
<%= image_tag f.image.url(:small) %>
<%= image_tag 'fatcrosswhite.svg', class: 'imgover' %>
</div>
<% end %>
</div>
<% end %>
</div>
link to Photographephotos#destroy is remote and there's an id like "destruction134"
photographephotos_controller.rb
def destroy
#imagedestroyed = Photographephoto.find(params[:id])
#imagedestroyedid = #imagedestroyed.id
#imagedestroyed.image = nil
#imagedestroyed.save
#imagedestroyed.destroy
respond_to do |format|
format.js
end
end
views/photographephotos/destroy.js.erb
var destroyelement = document.getElementById("<%= "destruction"+#imagedestroyedid.to_s %>");
destroyelement.parentNode.remove();
Problem is the file is indeed deleted but I have to refresh the page to see it removed. It seems the javascript is not effective. (I am trying to remove the parent of the link which is a Bootstrap DIV)
So I have gotten a better understanding of the issue I have involving Javascript. The problem lies within the fact that after the AJAX call to refresh the contents of a div, the contents within that div are unlinked or uninitialized for the Javascript. What I am trying to do is make my list of activities sortable for the user. I use a priority field to save the order of the activities so when the user refreshes or leaves the page, then the order is maintained.
The problem I am receiving is the following:
ActiveRecord::RecordNotFound (Couldn't find Activity with 'id'=item):
and as a result, the activity order will not be saved. This happens after the AJAX call and refresh and it works normally beforehand, saving the order and whatnot. I have tried some solutions, such as one and moving the Javascript over into the partial to no success.
I believe the error above is the result of the activity not linking correctly with the Javascript file which leads it to an id of "item" so does anyone know how to fix this issue or any advice on how to fix it? Thanks!
Main View:
<!-- home.html.erb -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
</head>
<!-- the jScrollPane script -->
<!--IF THE USER IS LOGGED IN, DISPLAY THE FOLLOWING -->
<% if current_user %>
<!--
<style>
.navbar {
background-color:#2F4F4F
}
</style>
-->
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href='home'>TimeTracker</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li>Signed in as <%=current_user.email %></li>
<li>
<%= link_to 'Sign Out', sign_out_path, method: :delete %>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css">
<h1 align = "center">Activities</h1>
<div id = 'activity_container'>
<ul id="Categories" class="connectedSortable">
<% #categories.each do |cats| %>
<% if cats.user_id == current_user.id%>
<div class="panel-group">
<div class="panel text-left">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#collapse<%= cats.id%>">
<%= cats.c_name %>
</a>
</h4>
</div>
<div id="collapse<%= cats.id%>" class="panel-collapse collapse">
<ul id="category_activities" class=".connectedSortable">
<% cats.activities.each do |activity| %>
<li class="list-group-item" >
<% if activity.hidden == false || activity.hidden == nil%>
<label class="my_label"><%= activity.a_name %></label>
<!-- Delete Activity -->
<%= link_to destroy_act_path(activity.id), method: :delete, data: { confirm: "Are you sure?" } do %>
<i class="fa fa-trash-o" aria-hidden="true" title="Delete"></i>
<% end %>
<!-- Edit activity -->
<%= link_to edit_act_path(activity.id)do %>
<!--<button class="editActivity" style="border:none; padding:0; background-color: transparent">-->
<i class="fa fa-pencil fa-fw" aria-hidden="true" title="Edit" id="editActivity"></i>
<!--</button>-->
<% end %>
<!-- Hide activity -->
<%= link_to hide_act_path(activity.id), method: :post do %>
<i class="fa fa-eye" aria-hidden="true" title="Hide" id="item"></i>
<% end %>
<% end %>
<% end %>
</li>
</ul>
</div>
</div>
</div>
<% end %>
<% end %>
</ul>
<ul id="Activities" class="connectedSortable" >
<!-- List each activity in database -->
<% #activities.each do |activity| %>
<% if (activity.hidden == false || activity.hidden == nil) && activity.category_id == nil %>
<li class="list-group-item" id='<%=activity.id%>' style="list-style: none;">
<!-- Display activity name -->
<label class="my_label"><%= activity.a_name %></label>
<!-- Delete Activity -->
<%= link_to destroy_act_path(activity.id), method: :delete, data: { confirm: "Are you sure?" }, remote: true do %>
<i class="fa fa-trash-o" aria-hidden="true" title="Delete"></i>
<% end %>
<!-- Edit activity -->
<%= link_to edit_act_path(activity.id)do %>
<button class="editActivity" style="border:none; padding:0; background-color: transparent">
<i class="fa fa-pencil fa-fw" aria-hidden="true" title="Edit" id="editActivity"></i>
</button>
<% end %>
<!-- Hide activity -->
<%= link_to hide_act_path(activity.id), method: :post do %>
<i class="fa fa-eye" aria-hidden="true" title="Hide" id="item"></i>
<% end %>
</li> <!-- End of list item -->
<% end %> <!-- End of if statement -->
<% end %> <!-- End of activity loop -->
</ul>
</div>
<ul class="pager">
<li class="previous"><span aria-hidden="true">←</span>Previous </li>
<li class="next"> Next<span aria-hidden="true">→</span></li>
<!-- *****************NEW*********************** -->
<%= form_for #activity, :url => create_act_path, remote: true, data: {type: 'script'} do |a| %>
<%= a.text_field :a_name, id: 'a_name_field', placeholder: 'Activity Name'%>
<%= a.select :category_id, Category.all.collect { |c| [c.c_name, c.id] }, include_blank: "--No Category--" %>
<%= a.submit 'Create', id: 'submitButton', class: 'btn btn-primary'%>
<% end %>
<%= form_for #category, :url => create_cat_path, remote: true do |c| %>
<%= c.text_field :c_name, id: 'c_name_field', placeholder: 'Category Name'%>
<%= c.submit 'Create', id: 'submitButton', class: 'btn btn-primary'%>
<% end %>
<!-- Button for showing all hidden items -->
<%= link_to unhide_act_path, method: :post do %>
<button class="showHidden" >Show Hidden</button>
<% end %>
<!-- Button to sort -->
<button class="sortActivity">Sort</button>
<button class="doneSorting">Done Sorting</button>
<!-- ***************************************** -->
</ul>
<!-- IF THE USER IS NOT LOGGED IN, DISPLAY THE FOLLOWING -->
<% else %>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">TimeTracker</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li class="active">
</li>
</ul>
</div>
</div>
</nav>
<div class="loginContainer" align="center">
<h1 align="center">
<b>
Please log in or sign up
</b>
</h1>
<div class="container">
<br>
<%= button_to 'Login', sign_in_path, :method => 'get', class: 'btn' %>
<br>
<%= button_to 'Sign Up', sign_up_path, :method => 'get', class: 'btn' %>
</div>
<!--<div class="container" style="background-color:#D3D3D3">
<input type="checkbox" checked="checked"> Remember me
<span class="psw">Forgot <a align="center" href="#">password?</a></span>
</div> -->
</div>
<% end %>
<script type="text/javascript">
function changeImg(img) {
if (img.src == "<%=asset_path('_unfilledbubble.png')%>"){
img.src = "<%=asset_path('_filledbubble.png')%>";
}
else {
img.src = "<%=asset_path('_unfilledbubble.png')%>";
}
}
</script>
<script type="text/javascript">
$(document).ready(function() {
$(function () {
$('.scroll-pane').jScrollPane({showArrows: true});
});
});
</script>
<script>
$(document).ready(function(){
function callAll(){
set_positions = function(){
// loop through and give each task a data-pos
// attribute that holds its position in the DOM
$('.list-group-item').each(function(i){
$(this).attr("data-pos",i+1);
});
}
// ready = function(){
// call set_positions function
set_positions();
// ************NEW execept for #Activities
$('#Activities').sortable({
connectWith: ".connectedSortable"
});
$('#Activities').disableSelection();
// $('#Categories').sortable({
// connectWith: ".connectedSortable"
// });
// $('#Categories').disableSelection();
$('#category_activities').sortable({
connectWith: ".connectedSortable"
});
$('#category_activities').disableSelection();
// *******end of NEW
$('#Activities li').on('click','li',function (){
var myid = $(this).attr('id');
alert(myid);
});
// after the order changes
$('#Activities').sortable().bind('sortupdate', function(e, ui) {
// array to store new order
var updated_order = []
// set the updated positions
set_positions();
// populate the updated_order array with the new task positions
$('#Activities li').each(function(i){
updated_order.push({ id: $(this).attr('id'), position: i });
});
// send the updated order via ajax
$.ajax({
type: "PUT",
url: '/home/sort',
data: { order: updated_order }
});
});
}
$(document).ajaxComplete(callAll());
})
</script>
Partial View:
<!-- List each activity in database -->
<% #activities.each do |activity| %>
<% if (activity.hidden == false || activity.hidden == nil) && activity.category_id == nil %>
<li class="list-group-item" id="item" data-id="<%activity.id%>" style="list-style: none;">
<!-- Display activity name -->
<label class="my_label"><%= activity.a_name %></label>
<!-- Delete Activity -->
<%= link_to destroy_act_path(activity.id), method: :delete, data: { confirm: "Are you sure?" }, remote: true do %>
<i class="fa fa-trash-o" aria-hidden="true" title="Delete"></i>
<% end %>
<!-- Edit activity -->
<%= link_to edit_act_path(activity.id)do %>
<button class="editActivity" style="border:none; padding:0; background-color: transparent">
<i class="fa fa-pencil fa-fw" aria-hidden="true" title="Edit" id="editActivity"></i>
</button>
<% end %>
<!-- Hide activity -->
<%= link_to activity, method: :post, :controller => :activities, :action => :set_hidden_true, remote: true do %>
<button class="hideActivity" style="border:none; padding:0; background-color: transparent">
<i class="fa fa-eye" aria-hidden="true" title="Hide" id="item"></i>
</button>
<% end %>
</li> <!-- End of list item -->
<% end %> <!-- End of if statement -->
<% end %> <!-- End of activity loop -->
Create Activity JS File:
<!--create_activity.js.erb-->
$('#Activities').html("<%= j (render 'object') %>");
Home Controller:
class HomeController < ApplicationController
respond_to :html, :js
def new
end
def index
end
def home
#activities = Activity.all
#activity = Activity.new
#categories = Category.all
#category = Category.new
end
def create_activity
#activity = Activity.create(activity_params)
#activity.user_id = current_user.id
#activity.priority = #activity.id
#object = Category.all
#activities = Activity.all
#categories = Category.all
if #activity.save
flash[:success] = 'Activity created successfully'
else
flash[:notice] ='ERROR: Activity could not be create'
end
end
def create_category
#category = Category.new(category_params)
#category.user_id = current_user.id
##category.priority = #category.id
#object = Category.all
#activities = Activity.all
#categories = Category.all
##category.priority = #category.id
if #category.save!
flash[:success] = 'Category created successfully!'
else
flash[:error] = 'ERROR: Category was not saved!'
end
end
def destroy_activity
#activity = Activity.find(params[:id])
#activity.destroy
#object = Category.all
#activities = Activity.all
#categories = Category.all
end
def welcome
end
def hide_activity
#object = Category.all
#activities = Activity.all
#categories = Category.all
#activity = Activity.find(params[:id])
#activity.update_attribute(:hidden, true)
respond_to do |format|
format.html {redirect_to activities_url}
format.js
end
end
#NEW 4/15
def edit_activity
#activity = Activity.find(params[:id])
end
def update_activity
#activity = Activity.find(params[:id])
if #activity.update_attributes(activity_params)
flash[:success] = 'Activity updated successfully!'
else
flash[:notice] = 'Activity was not updated'
end
end
def unhide_all
#object = Category.all
#activities = Activity.all
#categories = Category.all
#activities = Activity.all
#activities.update_all(hidden: false)
# redirect_to root_path
end
def sort
params[:order].each do |key, value|
Activity.find(value[:id]).update_attribute(:priority, value[:position])
end
render :nothing => true
end
private
def activity_params
params.require(:activity).permit(:a_name, :category_id)
end
def category_params
params.require(:category).permit(:c_name)
end
end
UPDATE
I have tried the following and as a test, replaced my script in the html with the following:
$('#Activities').on('click','li',function (){
var myid = $(this).attr('id');
alert(myid);
});
Before the Ajax, when I click on an activity, it correctly gives me its id. However, after doing an Ajax call, then when I try clicking on an activity, I get the same error where it claims it cannot find an activity with "id=item"
You have a lot of options here, one option is to change the bind to the document or the body and not directly to the id of the element because this is created dinamically, for example:
$("body").on('click',"#Activities" ,function () {
var myid = $(this).attr('id');
alert(myid);
});
you can initialize the event on the ajax request again when the element is rendered that is not recommended
or use plugins like https://github.com/adampietrasiak/jquery.initialize that can reinit the plugins if you bind it to a class, id or another selector.
I've created an example where you will be able to create a Person from the index page using an AJAX request. After the Person is created a new list of people is send to the index page. To simulate your JavaScript I set the background-color of every element to blue using jQuery.
Let's start with the index.html.erb itself.
<!-- app/views/people/index.html.erb -->
<p id="notice"><%= notice %></p>
<h1>People</h1>
<table>
<thead>
<tr>
<th>First name</th>
<th>Last name</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody id="people_tbody">
<%= render 'people', people: #people %>
</tbody>
</table>
<%= render('form', person: #people.new) %>
Next the two partials, _people.html.erb:
<!-- app/views/people/_people.html.erb -->
<% people.each do |person| %>
<tr>
<td><%= person.first_name %></td>
<td><%= person.last_name %></td>
<td><%= link_to 'Show', person %></td>
<td><%= link_to 'Edit', edit_person_path(person) %></td>
<td><%= link_to 'Destroy', person, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
and _form.html.erb from which the AJAX request gets fired:
<!-- app/views/people/_form.html.erb -->
<%= form_for(person, remote: true) do |f| %> <!-- remote true, makes it an AJAX call -->
<% if person.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(person.errors.count, "error") %> prohibited this person from being saved:</h2>
<ul>
<% person.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :first_name %>
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name %>
<%= f.text_field :last_name %>
</div>
<div class="actions">
<%= f.submit %> <!-- when submit is clicked the AJAX request is fired to PeopleController#create -->
</div>
<% end %>
To simulate your JavaScript problem I have the following file:
// app/assets/javascripts/people.js
function init_people() {
$('#people_tbody tr').css('background-color', 'lightblue')
}
$(document).ready(init_people)
This gives all rows a light blue background.
As you can see I'm using AJAX to send the filled in form because the remote: true is set. If the form is submitted the request will arrive in PeopleController#create, which looks like this:
# app/controllers/people_controller.rb
class PeopleController < ApplicationController
before_action :set_person, only: [:show, :edit, :update, :destroy]
# GET /people
# GET /people.json
def index
#people = Person.all
end
# GET /people/1
# GET /people/1.json
def show
end
# GET /people/new
def new
#person = Person.new
end
# GET /people/1/edit
def edit
end
# POST /people
# POST /people.json
def create # AJAX request arrives here
#person = Person.new(person_params)
respond_to do |format|
if #person.save
format.html { redirect_to #person, notice: 'Person was successfully created.' }
format.json { render :show, status: :created, location: #person }
# I added the underlying line to handle the AJAX response.
format.js { render :index, status: :created, location: #person }
else
format.html { render :new }
format.json { render json: #person.errors, status: :unprocessable_entity }
# I added the underlying line to handle the AJAX response.
format.js { render nothing: true }
end
end
end
# PATCH/PUT /people/1
# PATCH/PUT /people/1.json
def update
respond_to do |format|
if #person.update(person_params)
format.html { redirect_to #person, notice: 'Person was successfully updated.' }
format.json { render :show, status: :ok, location: #person }
else
format.html { render :edit }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
# DELETE /people/1
# DELETE /people/1.json
def destroy
#person.destroy
respond_to do |format|
format.html { redirect_to people_url, notice: 'Person was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_person
#person = Person.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def person_params
params.require(:person).permit(:first_name, :last_name)
end
end
As you can see I added two lines to handle the js format in PeopleController#create. If the render comes from format.js { ... } rails knows to pick the index.js.erb file, and not the index.html.erb file. If you don't want this behavior you can specify the specific file.
My index.js.erb looks like this:
// app/views/people/index.js.erb
$('#people_tbody').html("<%= j(render('people', people: Person.all)) %>")
This replaces the contents of the #people_tbody with the new set op people (similar to your example). But now I've the same problem as you. The JavaScript isn't triggered anymore, and the background of every row is just white. To trigger the JavaScript over the new loaded content I just need to call the init function. This means any logic you want to apply after the document is ready and after an AJAX request should be extracted to a separate function. I placed my logic in the function init_people().
This means the index.js.erb should look like this:
// app/views/people/index.js.erb
$('#people_tbody').html("<%= j(render('people', people: Person.all)) %>")
init_people()
Now, after the AJAX content is loaded, the init_people() function is triggered setting up the JavaScript for the new loaded content.
I have a basic to do type app and I am trying to change the variable completed for an item to the current date/time when I click a checkbox. I found this post, which has led me to the following code structure:
My lists#show, on which items are created, checked off (updated), edited, and deleted:
<div class="container">
<div class="row" style="height: 70px"></div>
</div>
<div class="col-xs-10 col-xs-push-1 container">
<div class="md-well">
<h1 class="text-center"><%= #list.name %></h1>
<% if #items.count == 0 %>
<h4 class="text-center">You don't have any items on this list yet! Want to add some?<h4>
<% elsif #items.count == 1 %>
<h4 class="text-center">Only <%= #items.count %> Item To Go!</h4>
<% else %>
<h4 class="text-center">You Have <%= #items.count %> Items To Go!</h4>
<% end %>
<%= render 'items/form' %>
<% #items.each do |item|%>
<p>
<%= form_for [#list, item], class: "inline-block", id: 'item<%= item.id %>' do |f| %>
<%= f.check_box :completed, :onclick => "$this.parent.submit()" %>
<% end %>
<%= item.name %>
( <%= link_to "Delete", list_item_path(#list, item), method: :delete %> )
</p>
<% end %>
<div class="text-center">
<%= link_to "Back to My Lists", lists_path %>
</div> <!-- text-center -->
</div> <!-- well -->
</div> <!-- container -->
Here is my update method in my items_controller (which I believe has jurisdiction instead of the lists_controller even though it is the lists#show page because it is an item being updated:
def update
#list = List.friendly.find(params[:list_id])
#item = #list.items.find(params[:id])
#item.name = params[:item][:name]
#item.delegated_to = params[:item][:delegated_to]
#item.days_til_expire = params[:item][:days_til_expire]
#item.completed = params[:item][:completed]
#item.user = current_user
if #item.update_attributes(params[:item])
#item.completed = Time.now
end
if #item.save
flash[:notice] = "List was updated successfully."
redirect_to #list
else
flash.now[:alert] = "Error saving list. Please try again."
render :edit
end
end
Here is what is currently appearing:
And here are the two problems I'm having:
LESS IMPORTANT PROBLEM: The checkboxes should be displayed inline with the list items but aren't. My class inline-block simply makes links to this in the application.scss file:
.inline-block {
display: inline-block !important;
}
MORE IMPORTANT PROBLEM: Even after the checkbox is clicked, the value for completed remains nil as per my console:
[6] pry(main)> Item.where(name: "Feed Dexter")
Item Load (0.1ms) SELECT "items".* FROM "items" WHERE "items"."name" = ? [["name", "Feed Dexter"]]
=> [#]
Any ideas how to make this functional?
I can't get my form to reset correctly. It submits and it goes to the database but everything remains on the form.
Here is my code:
DogsController
def create
#dog = current_user.dogs.new(params[:dog])
if #dog.save
format.js
else
format.js
end
end
dog/create.js.erb
$('.add-dog-form').html('<%= escape_javascript(render(:partial => 'dogs/form', locals: { dog: #dog })) %>');
$('.add-dog-form > form')[0].reset(); // doesn't work
dog/new.js.erb
$('.add-dog-form').html('<%= escape_javascript(render(:partial => 'dogs/form', locals: { dog: #dog })) %>');
dogs/_form
<%= form_for(#dog, :remote => true) do |f| %>
<%= f.label :name, "Name" %>
<%= f.text_field :name %>
<%= f.submit "Add Dog" %>
<% end %>
I create dogs at the Pets view instead of the dogs.
PetsController
def add
#dog = Dog.new
#cat = Cat.new
#bird = Bird.new
end
pets/add.html.erb
I click on the tab which changes it to the Dog Tab using Twitter Bootstraps Tabbable Nav ability
<div class="tabbable">
<ul class="nav nav-tabs">
<li class="active">
Cat
</li>
<li>
Dog
</li>
<li>
Bird
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active add-cat-form" id="tab1">
<%= render "cats/form" %>
</div>
<div class="tab-pane add-dog-form" id="tab2">
<%= render "dogs/form" %>
</div>
<div class="tab-pane add-bird-form" id="tab3">
<%= render "birds/form" %>
</div>
</div>
</div>
How can I reset the form if it gets created?
Try giving the form an id:
<%= form_for(#dog, :remote => true, :html => { :id => 'dog_form' } ) do |f| %>
and $('#dog_form')[0].reset();.
Alternatively, you can do $(":input:not(input[type=submit])").val("");.
Well it seems my error was in my files themselves. I had created the js files as partials instead of regular pages. i.e. _create.js.erb should be create.js.erb. I also had to add respond_to do |format| in the controller create action. Now I got everything working correctly.