Ajout de livre et suppression de livre sans recharger la page d’index OK

master
Nolwenn LAVIELLE 3 years ago
parent ef36e1f588
commit f88d886332
  1. 1
      Gemfile
  2. 3
      Gemfile.lock
  3. 4
      app/assets/javascripts/application.js
  4. 3
      app/assets/javascripts/emprunts.coffee
  5. 1188
      app/assets/javascripts/jquery.tabledit.js
  6. 37
      app/assets/javascripts/livres.coffee
  7. 47
      app/assets/javascripts/livres.js
  8. 613
      app/assets/javascripts/rails.tabledit.js
  9. 4
      app/assets/stylesheets/_mixin.sass
  10. 2
      app/assets/stylesheets/application.sass
  11. 3
      app/assets/stylesheets/emprunts.scss
  12. 1
      app/assets/stylesheets/scaffolds.scss
  13. 74
      app/controllers/emprunts_controller.rb
  14. 54
      app/controllers/livres_controller.rb
  15. 2
      app/helpers/emprunts_helper.rb
  16. 9
      app/helpers/livres_helper.rb
  17. 2
      app/models/emprunt.rb
  18. 2
      app/views/emprunts/_emprunt.json.jbuilder
  19. 27
      app/views/emprunts/_form.html.erb
  20. 6
      app/views/emprunts/edit.html.erb
  21. 29
      app/views/emprunts/index.html.erb
  22. 1
      app/views/emprunts/index.json.jbuilder
  23. 5
      app/views/emprunts/new.html.erb
  24. 14
      app/views/emprunts/show.html.erb
  25. 1
      app/views/emprunts/show.json.jbuilder
  26. 1
      app/views/layouts/application.html.erb
  27. 15
      app/views/livres/_form.html.erb
  28. 11
      app/views/livres/_livre.html.erb
  29. 2
      app/views/livres/_livre.json.jbuilder
  30. 3
      app/views/livres/create.js.erb
  31. 3
      app/views/livres/destroy.js.erb
  32. 45
      app/views/livres/index.html.erb
  33. 1
      app/views/livres/index.json.jbuilder
  34. 1
      app/views/livres/new.js.erb
  35. 29
      app/views/livres/show.html.erb
  36. 1
      app/views/livres/show.json.jbuilder
  37. 1
      config/initializers/assets.rb
  38. 4
      config/routes.rb
  39. 10
      db/migrate/20200217133444_create_emprunts.rb
  40. 9
      db/schema.rb
  41. 48
      test/controllers/emprunts_controller_test.rb
  42. 9
      test/fixtures/emprunts.yml
  43. 7
      test/models/emprunt_test.rb
  44. 45
      test/system/emprunts_test.rb

@ -19,6 +19,7 @@ gem 'jbuilder', '~> 2.5'
gem 'bootsnap', '>= 1.1.0', require: false
gem 'bootstrap', '~> 4.3.1'
gem 'font-awesome-rails'
gem 'jquery-rails'
gem 'jquery-ui-rails'

@ -87,6 +87,8 @@ GEM
eventmachine (1.2.7)
execjs (2.7.0)
ffi (1.12.2)
font-awesome-rails (4.7.0.5)
railties (>= 3.2, < 6.1)
formatador (0.2.5)
globalid (0.4.2)
activesupport (>= 4.2.0)
@ -256,6 +258,7 @@ DEPENDENCIES
capybara (>= 2.15)
chromedriver-helper
coffee-rails (~> 4.2)
font-awesome-rails
guard-livereload
guard-rails
jbuilder (~> 2.5)

@ -12,6 +12,6 @@
//
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require jquery
//= require jquery.tabledit
//= require_tree .
//= require turbolinks

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

File diff suppressed because it is too large Load Diff

@ -1,37 +0,0 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
$('#livres').Tabledit({
url: '/livres/index',
editButton: true,
buttons: {
edit: {
class: 'btn btn-sm btn-default',
html: '<span class="glyphicon glyphicon-pencil"></span>',
action: 'edit'
},
delete: {
class: 'btn btn-sm btn-default',
html: '<span class="glyphicon glyphicon-trash"></span>',
action: 'delete'
},
save: {
class: 'btn btn-sm btn-success',
html: 'Save'
},
restore: {
class: 'btn btn-sm btn-warning',
html: 'Restore',
action: 'restore'
},
confirm: {
class: 'btn btn-sm btn-danger',
html: 'Confirm'
}
},
columns: {
identifier: [0, 'id'],
editable: [[1, 'titre'], [2, 'auteur'], [3, 'synopsis'], [4, 'style'], [5, 'isbn']]
}
});

@ -0,0 +1,47 @@
$('#livres').Tabledit({
url: '/livres/tabledit',
editButton: true,
deleteButton: true,
buttons: {
edit: {
class: 'btn btn-dark',
html: '<span class="fa fa-edit"></span> Edit',
action: '/livres/tabledit'
},
delete: {
class: 'btn btn-dark',
html: '<span class="fa fa-trash"></span> Delete',
action: 'delete'
},
save: {
class: 'btn btn-success btn-sm',
html: '<span class="fa fa-save"></span> Save',
action: '/livres/update'
},
restore: {
class: 'btn btn-warning',
html: '<span class="fa fa-trash-restore"></span> Restore',
action: 'restore'
},
confirm: {
class: 'btn btn-danger btn-sm',
html: '<span class="fa fa-check"></span> Confirm'
}
},
hideIdentifier: true,
columns: {
identifier: [0, 'id'],
editable: [[1, 'titre'], [2, 'auteur'], [3, 'synopsis'], [4, 'style'], [5, 'isbn']]
},
onSuccess: function(data, textStatus, jqXHR) {
console.log('onSuccess(data, textStatus, jqXHR)');
console.log(data);
console.log(textStatus);
console.log(jqXHR);
},
onAjax: function(action, serialize) {
console.log('onAjax(action, serialize)');
console.log(action);
console.log(serialize);
}
});

@ -0,0 +1,613 @@
/*!
* Tabledit v1.2.3 (https://github.com/markcell/jQuery-Tabledit)
* Copyright (c) 2015 Celso Marques
* Licensed under MIT (https://github.com/markcell/jQuery-Tabledit/blob/master/LICENSE)
*/
/**
* @description Inline editor for HTML tables compatible with Bootstrap 4 and Rails
* @version 1.0
* @author Nolwenn Lavielle
* @origin jQuery-Tabledit
*/
if (typeof jQuery === 'undefined') {
throw new Error('Tabledit requires jQuery library.');
}
(function($) {
'use strict';
$.fn.Tabledit = function(options) {
if (!this.is('table')) {
throw new Error('Tabledit only works when applied to a table.');
}
var $table = this;
var defaults = {
url: window.location.href,
inputClass: 'form-control input-sm',
toolbarClass: 'btn-toolbar',
groupClass: 'btn-group btn-group-sm',
dangerClass: 'danger',
warningClass: 'warning',
mutedClass: 'text-muted',
eventType: 'click',
rowIdentifier: 'id',
hideIdentifier: false,
autoFocus: true,
editButton: true,
deleteButton: true,
saveButton: true,
restoreButton: true,
buttons: {
edit: {
class: 'btn btn-sm btn-primary',
html: '<span class="glyphicon glyphicon-pencil"></span>',
action: 'edit'
},
delete: {
class: 'btn btn-sm btn-primary',
html: '<span class="glyphicon glyphicon-trash"></span>',
action: 'delete'
},
save: {
class: 'btn btn-sm btn-success',
html: 'Save'
},
restore: {
class: 'btn btn-sm btn-warning',
html: 'Restore',
action: 'restore'
},
confirm: {
class: 'btn btn-sm btn-danger',
html: 'Confirm'
}
},
onDraw: function() { return; },
onSuccess: function() { return; },
onFail: function() { return; },
onAlways: function() { return; },
onAjax: function() { return; }
};
var settings = $.extend(true, defaults, options);
var $lastEditedRow = 'undefined';
var $lastDeletedRow = 'undefined';
var $lastRestoredRow = 'undefined';
/**
* Draw Tabledit structure (identifier column, editable columns, toolbar column).
*
* @type {object}
*/
var Draw = {
columns: {
identifier: function() {
// Hide identifier column.
if (settings.hideIdentifier) {
$table.find('th:nth-child(' + parseInt(settings.columns.identifier[0]) + 1 + '), tbody td:nth-child(' + parseInt(settings.columns.identifier[0]) + 1 + ')').hide();
}
var $td = $table.find('tbody td:nth-child(' + (parseInt(settings.columns.identifier[0]) + 1) + ')');
$td.each(function() {
// Create hidden input with row identifier.
var span = '<span class="tabledit-span tabledit-identifier">' + $(this).text() + '</span>';
var input = '<input class="tabledit-input tabledit-identifier" type="hidden" name="' + settings.columns.identifier[1] + '" value="' + $(this).text() + '" disabled>';
// Add elements to table cell.
$(this).html(span + input);
// Add attribute "id" to table row.
$(this).parent('tr').attr(settings.rowIdentifier, $(this).text());
});
},
editable: function() {
for (var i = 0; i < settings.columns.editable.length; i++) {
var $td = $table.find('tbody td:nth-child(' + (parseInt(settings.columns.editable[i][0]) + 1) + ')');
$td.each(function() {
// Get text of this cell.
var text = $(this).text();
// Add pointer as cursor.
if (!settings.editButton) {
$(this).css('cursor', 'pointer');
}
// Create span element.
var span = '<span class="tabledit-span">' + text + '</span>';
// Check if exists the third parameter of editable array.
if (typeof settings.columns.editable[i][2] !== 'undefined') {
// Create select element.
var input = '<select class="tabledit-input ' + settings.inputClass + '" name="' + settings.columns.editable[i][1] + '" style="display: none;" disabled>';
// Create options for select element.
$.each(jQuery.parseJSON(settings.columns.editable[i][2]), function(index, value) {
if (text === value) {
input += '<option value="' + index + '" selected>' + value + '</option>';
} else {
input += '<option value="' + index + '">' + value + '</option>';
}
});
// Create last piece of select element.
input += '</select>';
} else {
// Create text input element.
var input = '<input class="tabledit-input ' + settings.inputClass + '" type="text" name="' + settings.columns.editable[i][1] + '" value="' + $(this).text() + '" style="display: none;" disabled>';
}
// Add elements and class "view" to table cell.
$(this).html(span + input);
$(this).addClass('tabledit-view-mode');
});
}
},
toolbar: function() {
if (settings.editButton || settings.deleteButton) {
var editButton = '';
var deleteButton = '';
var saveButton = '';
var restoreButton = '';
var confirmButton = '';
// Add toolbar column header if not exists.
if ($table.find('th.tabledit-toolbar-column').length === 0) {
$table.find('tr:first').append('<th class="tabledit-toolbar-column"></th>');
}
// Create edit button.
if (settings.editButton) {
editButton = '<button type="button" class="tabledit-edit-button ' + settings.buttons.edit.class + '" style="float: none;">' + settings.buttons.edit.html + '</button>';
}
// Create delete button.
if (settings.deleteButton) {
deleteButton = '<button type="button" class="tabledit-delete-button ' + settings.buttons.delete.class + '" style="float: none;">' + settings.buttons.delete.html + '</button>';
confirmButton = '<button type="button" class="tabledit-confirm-button ' + settings.buttons.confirm.class + '" style="display: none; float: none;">' + settings.buttons.confirm.html + '</button>';
}
// Create save button.
if (settings.editButton && settings.saveButton) {
saveButton = '<button type="button" class="tabledit-save-button ' + settings.buttons.save.class + '" style="display: none; float: none;">' + settings.buttons.save.html + '</button>';
}
// Create restore button.
if (settings.deleteButton && settings.restoreButton) {
restoreButton = '<button type="button" class="tabledit-restore-button ' + settings.buttons.restore.class + '" style="display: none; float: none;">' + settings.buttons.restore.html + '</button>';
}
var toolbar = '<div class="tabledit-toolbar ' + settings.toolbarClass + '" style="text-align: left;">\n\
<div class="' + settings.groupClass + '" style="float: none;">' + editButton + deleteButton + '</div>\n\
' + saveButton + '\n\
' + confirmButton + '\n\
' + restoreButton + '\n\
</div></div>';
// Add toolbar column cells.
$table.find('tbody>tr').append('<td style="white-space: nowrap; width: 1%;">' + toolbar + '</td>');
}
}
}
};
/**
* Change to view mode or edit mode with table td element as parameter.
*
* @type object
*/
var Mode = {
view: function(td) {
// Get table row.
var $tr = $(td).parent('tr');
// Disable identifier.
$(td).parent('tr').find('.tabledit-input.tabledit-identifier').prop('disabled', true);
// Hide and disable input element.
$(td).find('.tabledit-input').blur().hide().prop('disabled', true);
// Show span element.
$(td).find('.tabledit-span').show();
// Add "view" class and remove "edit" class in td element.
$(td).addClass('tabledit-view-mode').removeClass('tabledit-edit-mode');
// Update toolbar buttons.
if (settings.editButton) {
$tr.find('button.tabledit-save-button').hide();
$tr.find('button.tabledit-edit-button').removeClass('active').blur();
}
},
edit: function(td) {
Delete.reset(td);
// Get table row.
var $tr = $(td).parent('tr');
// Enable identifier.
$tr.find('.tabledit-input.tabledit-identifier').prop('disabled', false);
// Hide span element.
$(td).find('.tabledit-span').hide();
// Get input element.
var $input = $(td).find('.tabledit-input');
// Enable and show input element.
$input.prop('disabled', false).show();
// Focus on input element.
if (settings.autoFocus) {
$input.focus();
}
// Add "edit" class and remove "view" class in td element.
$(td).addClass('tabledit-edit-mode').removeClass('tabledit-view-mode');
// Update toolbar buttons.
if (settings.editButton) {
$tr.find('button.tabledit-edit-button').addClass('active');
$tr.find('button.tabledit-save-button').show();
}
}
};
/**
* Available actions for edit function, with table td element as parameter or set of td elements.
*
* @type object
*/
var Edit = {
reset: function(td) {
$(td).each(function() {
// Get input element.
var $input = $(this).find('.tabledit-input');
// Get span text.
var text = $(this).find('.tabledit-span').text();
// Set input/select value with span text.
if ($input.is('select')) {
$input.find('option').filter(function() {
return $.trim($(this).text()) === text;
}).attr('selected', true);
} else {
$input.val(text);
}
// Change to view mode.
Mode.view(this);
});
},
submit: function(td) {
// Send AJAX request to server.
var ajaxResult = ajax(settings.buttons.edit.action);
if (ajaxResult === false) {
return;
}
$(td).each(function() {
// Get input element.
var $input = $(this).find('.tabledit-input');
// Set span text with input/select new value.
if ($input.is('select')) {
$(this).find('.tabledit-span').text($input.find('option:selected').text());
} else {
$(this).find('.tabledit-span').text($input.val());
}
// Change to view mode.
Mode.view(this);
});
// Set last edited column and row.
$lastEditedRow = $(td).parent('tr');
}
};
/**
* Available actions for delete function, with button as parameter.
*
* @type object
*/
var Delete = {
reset: function(td) {
// Reset delete button to initial status.
$table.find('.tabledit-confirm-button').hide();
// Remove "active" class in delete button.
$table.find('.tabledit-delete-button').removeClass('active').blur();
},
submit: function(td) {
Delete.reset(td);
// Enable identifier hidden input.
$(td).parent('tr').find('input.tabledit-identifier').attr('disabled', false);
// Send AJAX request to server.
var ajaxResult = ajax(settings.buttons.delete.action);
// Disable identifier hidden input.
$(td).parents('tr').find('input.tabledit-identifier').attr('disabled', true);
if (ajaxResult === false) {
return;
}
// Add class "deleted" to row.
$(td).parent('tr').addClass('tabledit-deleted-row');
// Hide table row.
$(td).parent('tr').addClass(settings.mutedClass).find('.tabledit-toolbar button:not(.tabledit-restore-button)').attr('disabled', true);
// Show restore button.
$(td).find('.tabledit-restore-button').show();
// Set last deleted row.
$lastDeletedRow = $(td).parent('tr');
},
confirm: function(td) {
// Reset all cells in edit mode.
$table.find('td.tabledit-edit-mode').each(function() {
Edit.reset(this);
});
// Add "active" class in delete button.
$(td).find('.tabledit-delete-button').addClass('active');
// Show confirm button.
$(td).find('.tabledit-confirm-button').show();
},
restore: function(td) {
// Enable identifier hidden input.
$(td).parent('tr').find('input.tabledit-identifier').attr('disabled', false);
// Send AJAX request to server.
var ajaxResult = ajax(settings.buttons.restore.action);
// Disable identifier hidden input.
$(td).parents('tr').find('input.tabledit-identifier').attr('disabled', true);
if (ajaxResult === false) {
return;
}
// Remove class "deleted" to row.
$(td).parent('tr').removeClass('tabledit-deleted-row');
// Hide table row.
$(td).parent('tr').removeClass(settings.mutedClass).find('.tabledit-toolbar button').attr('disabled', false);
// Hide restore button.
$(td).find('.tabledit-restore-button').hide();
// Set last restored row.
$lastRestoredRow = $(td).parent('tr');
}
};
/**
* Send AJAX request to server.
*
* @param {string} action
*/
function ajax(action)
{
var serialize = $table.find('.tabledit-input').serialize()
if (!serialize) {
return false;
}
serialize += '&action=' + action;
var result = settings.onAjax(action, serialize);
if (result === false) {
return false;
}
var jqXHR = $.post(settings.url, serialize, function(data, textStatus, jqXHR) {
if (action === settings.buttons.edit.action) {
$lastEditedRow.removeClass(settings.dangerClass).addClass(settings.warningClass);
setTimeout(function() {
//$lastEditedRow.removeClass(settings.warningClass);
$table.find('tr.' + settings.warningClass).removeClass(settings.warningClass);
}, 1400);
}
settings.onSuccess(data, textStatus, jqXHR);
}, 'json');
jqXHR.fail(function(jqXHR, textStatus, errorThrown) {
if (action === settings.buttons.delete.action) {
$lastDeletedRow.removeClass(settings.mutedClass).addClass(settings.dangerClass);
$lastDeletedRow.find('.tabledit-toolbar button').attr('disabled', false);
$lastDeletedRow.find('.tabledit-toolbar .tabledit-restore-button').hide();
} else if (action === settings.buttons.edit.action) {
$lastEditedRow.addClass(settings.dangerClass);
}
settings.onFail(jqXHR, textStatus, errorThrown);
});
jqXHR.always(function() {
settings.onAlways();
});
return jqXHR;
}
Draw.columns.identifier();
Draw.columns.editable();
Draw.columns.toolbar();
settings.onDraw();
if (settings.deleteButton) {
/**
* Delete one row.
*
* @param {object} event
*/
$table.on('click', 'button.tabledit-delete-button', function(event) {
if (event.handled !== true) {
event.preventDefault();
// Get current state before reset to view mode.
var activated = $(this).hasClass('active');
var $td = $(this).parents('td');
Delete.reset($td);
if (!activated) {
Delete.confirm($td);
}
event.handled = true;
}
});
/**
* Delete one row (confirm).
*
* @param {object} event
*/
$table.on('click', 'button.tabledit-confirm-button', function(event) {
if (event.handled !== true) {
event.preventDefault();
var $td = $(this).parents('td');
Delete.submit($td);
event.handled = true;
}
});
}
if (settings.restoreButton) {
/**
* Restore one row.
*
* @param {object} event
*/
$table.on('click', 'button.tabledit-restore-button', function(event) {
if (event.handled !== true) {
event.preventDefault();
Delete.restore($(this).parents('td'));
event.handled = true;
}
});
}
if (settings.editButton) {
/**
* Activate edit mode on all columns.
*
* @param {object} event
*/
$table.on('click', 'button.tabledit-edit-button', function(event) {
if (event.handled !== true) {
event.preventDefault();
var $button = $(this);
// Get current state before reset to view mode.
var activated = $button.hasClass('active');
// Change to view mode columns that are in edit mode.
Edit.reset($table.find('td.tabledit-edit-mode'));
if (!activated) {
// Change to edit mode for all columns in reverse way.
$($button.parents('tr').find('td.tabledit-view-mode').get().reverse()).each(function() {
Mode.edit(this);
});
}
event.handled = true;
}
});
/**
* Save edited row.
*
* @param {object} event
*/
$table.on('click', 'button.tabledit-save-button', function(event) {
if (event.handled !== true) {
event.preventDefault();
// Submit and update all columns.
Edit.submit($(this).parents('tr').find('td.tabledit-edit-mode'));
event.handled = true;
}
});
} else {
/**
* Change to edit mode on table td element.
*
* @param {object} event
*/
$table.on(settings.eventType, 'tr:not(.tabledit-deleted-row) td.tabledit-view-mode', function(event) {
if (event.handled !== true) {
event.preventDefault();
// Reset all td's in edit mode.
Edit.reset($table.find('td.tabledit-edit-mode'));
// Change to edit mode.
Mode.edit(this);
event.handled = true;
}
});
/**
* Change event when input is a select element.
*/
$table.on('change', 'select.tabledit-input:visible', function(event) {
if (event.handled !== true) {
// Submit and update the column.
Edit.submit($(this).parent('td'));
event.handled = true;
}
});
/**
* Click event on document element.
*
* @param {object} event
*/
$(document).on('click', function(event) {
var $editMode = $table.find('.tabledit-edit-mode');
// Reset visible edit mode column.
if (!$editMode.is(event.target) && $editMode.has(event.target).length === 0) {
Edit.reset($table.find('.tabledit-input:visible').parent('td'));
}
});
}
/**
* Keyup event on table element.
*
* @param {object} event
*/
$table.on('keyup', function(event) {
// Get input element with focus or confirmation button.
var $input = $table.find('.tabledit-input:visible');
var $button = $table.find('.tabledit-confirm-button');
if ($input.length > 0) {
var $td = $input.parents('td');
} else if ($button.length > 0) {
var $td = $button.parents('td');
} else {
return;
}
// Key?
switch (event.keyCode) {
case 9: // Tab.
if (!settings.editButton) {
Edit.submit($td);
Mode.edit($td.closest('td').next());
}
break;
case 13: // Enter.
Edit.submit($td);
break;
case 27: // Escape.
Edit.reset($td);
Delete.reset($td);
break;
}
});
return this;
};
}(jQuery));

@ -1,3 +1,3 @@
$main-background: #AF6D36
//$main-background: #AF6D36
$link-color: #AF6D36
//$link-color: #AF6D36

@ -1,7 +1,9 @@
/*
*= require font-awesome
*= require_tree .
*= require_self
*/
@import 'mixin'
@import 'bootstrap'
@import 'font-awesome'

@ -0,0 +1,3 @@
// Place all the styles related to the Emprunts controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

@ -0,0 +1,74 @@
class EmpruntsController < ApplicationController
before_action :set_emprunt, only: [:show, :edit, :update, :destroy]
# GET /emprunts
# GET /emprunts.json
def index
@emprunts = Emprunt.all
end
# GET /emprunts/1
# GET /emprunts/1.json
def show
end
# GET /emprunts/new
def new
@emprunt = Emprunt.new
end
# GET /emprunts/1/edit
def edit
end
# POST /emprunts
# POST /emprunts.json
def create
@emprunt = Emprunt.new(emprunt_params)
respond_to do |format|
if @emprunt.save
format.html { redirect_to @emprunt, notice: 'Emprunt was successfully created.' }
format.json { render :show, status: :created, location: @emprunt }
else
format.html { render :new }
format.json { render json: @emprunt.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /emprunts/1
# PATCH/PUT /emprunts/1.json
def update
respond_to do |format|
if @emprunt.update(emprunt_params)
format.html { redirect_to @emprunt, notice: 'Emprunt was successfully updated.' }
format.json { render :show, status: :ok, location: @emprunt }
else
format.html { render :edit }
format.json { render json: @emprunt.errors, status: :unprocessable_entity }
end
end
end
# DELETE /emprunts/1
# DELETE /emprunts/1.json
def destroy
@emprunt.destroy
respond_to do |format|
format.html { redirect_to emprunts_url, notice: 'Emprunt was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_emprunt
@emprunt = Emprunt.find(params[:id])
end
# Only allow a list of trusted parameters through.
def emprunt_params
params.require(:emprunt).permit(:idlivre, :nombre)
end
end

@ -2,7 +2,7 @@ class LivresController < ApplicationController
before_action :set_livre, only: [:show, :edit, :update, :destroy]
def index
@livres = Livre.all
@livres = Livre.order(id: :desc)
end
def new
@ -10,29 +10,61 @@ class LivresController < ApplicationController
end
def edit
@livre = Livre.find(params[:id])
end
def create
@livre = Livre.new(livre_params)
if @livre.save
redirect_to @livre, success: 'livre créé'
else
render new_livre_path
respond_to do |format|
if @livre.save(livre_params)
format.js
format.html { redirect_to livres_path, notice: 'livre was successfully added.' }
format.json { render :index, status: :ok, location: livres_path }
else
format.html { render :new }
format.json { render json: @livre.errors, status: :unprocessable_entity }
end
end
end
def update
if @livre.update(livre_params)
redirect_to @livre, success: 'livre mis à jour'
else
render edit_livre_path(@livre)
respond_to do |format|
if @livre.update(livre_params)
format.js
format.html { redirect_to @livre, success: 'livre mis à jour' }
format.json { render :index, status: :ok, location: livres_path }
else
format.html { render edit_livre_path(@livre) }
format.json { render json: @livre.errors, status: :unprocessable_entity }
end
end
end
# interaction avec table-edit
=begin
def tabledit
if params[:edit]
@livre = Livre.find(params[:id])
respond_to do |format|
if @livre.update(livre_params)
format.html { redirect_to @livre, notice: 'livre was successfully updated.' }
format.json { render :index, status: :ok, location: livres_path }
else
format.html { render :edit }
format.json { render json: @livre.errors, status: :unprocessable_entity }
end
end
end
end
=end
def destroy
@livre.destroy
redirect_to livres_url, success: 'livre supprimé'
respond_to do |format|
format.js
format.html { redirect_to livres_url, success: 'livre supprimé' }
format.json { head :no_content }
end
#redirect_to livres_url, success: 'livre supprimé'
end
private

@ -0,0 +1,2 @@
module EmpruntsHelper
end

@ -1,2 +1,11 @@
module LivresHelper
def link_to_add_book(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize + "_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
end

@ -0,0 +1,2 @@
class Emprunt < ApplicationRecord
end

@ -0,0 +1,2 @@
json.extract! emprunt, :id, :idlivre, :nombre, :created_at, :updated_at
json.url emprunt_url(emprunt, format: :json)

@ -0,0 +1,27 @@
<%= form_with(model: emprunt, local: true) do |form| %>
<% if emprunt.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(emprunt.errors.count, "error") %> prohibited this emprunt from being saved:</h2>
<ul>
<% emprunt.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :idlivre %>
<%= form.number_field :idlivre %>
</div>
<div class="field">
<%= form.label :nombre %>
<%= form.number_field :nombre %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>

@ -0,0 +1,6 @@
<h1>Editing Emprunt</h1>
<%= render 'form', emprunt: @emprunt %>
<%= link_to 'Show', @emprunt %> |
<%= link_to 'Back', emprunts_path %>

@ -0,0 +1,29 @@
<p id="notice"><%= notice %></p>
<h1>Emprunts</h1>
<table>
<thead>
<tr>
<th>Idlivre</th>
<th>Nombre</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @emprunts.each do |emprunt| %>
<tr>
<td><%= emprunt.idlivre %></td>
<td><%= emprunt.nombre %></td>
<td><%= link_to 'Show', emprunt %></td>
<td><%= link_to 'Edit', edit_emprunt_path(emprunt) %></td>
<td><%= link_to 'Destroy', emprunt, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Emprunt', new_emprunt_path %>

@ -0,0 +1 @@
json.array! @emprunts, partial: "emprunts/emprunt", as: :emprunt

@ -0,0 +1,5 @@
<h1>New Emprunt</h1>
<%= render 'form', emprunt: @emprunt %>
<%= link_to 'Back', emprunts_path %>

@ -0,0 +1,14 @@
<p id="notice"><%= notice %></p>
<p>
<strong>Idlivre:</strong>
<%= @emprunt.idlivre %>
</p>
<p>
<strong>Nombre:</strong>
<%= @emprunt.nombre %>
</p>
<%= link_to 'Edit', edit_emprunt_path(@emprunt) %> |
<%= link_to 'Back', emprunts_path %>

@ -0,0 +1 @@
json.partial! "emprunts/emprunt", emprunt: @emprunt

@ -30,5 +30,6 @@
<%= yield %>
</main>
<%#= javascript_include_tag 'livres.js' %>
</body>
</html>

@ -14,20 +14,15 @@
</div>
<% end %>
<%= form.label :titre %>
<%= form.text_field :titre %>
<%= form.text_field :titre, placeholder: :titre %>
<%= form.label :auteur %>
<%= form.text_field :auteur %>
<%= form.text_field :auteur, placeholder: :auteur %>
<%= form.label :synopsis %>
<%= form.textarea_field :synopsis %>
<%= form.text_field :synopsis, placeholder: :synopsis %>
<%= form.label :style %>
<%= form.text_field :style %>
<%= form.text_field :style, placeholder: :style %>
<%= form.label :isbn %>
<%= form.text_field :isbn %>
<%= form.text_field :isbn, placeholder: :isbn %>
<%= form.submit :submit %>
<% end %>

@ -0,0 +1,11 @@
<tr>
<td><%= livre.titre %></td>
<td><%= livre.auteur %></td>
<td><%= livre.synopsis[0..120] %></td>
<td><%= livre.style %></td>
<td><%= livre.isbn %></td>
<td>
<%= link_to 'Edit', edit_livre_path(livre), remote: true %>
<%= link_to 'Destroy', livre, method: :delete, data: { confirm: 'Supprimer la donnée de façon définitive ?', remote: true }, class: 'delete' %>
</td>
</tr>

@ -0,0 +1,2 @@
json.extract! livre, :id, :titre, :auteur, :synopsis, :style, :isbn
json.url livre_url(livre, format: :json)

@ -0,0 +1,3 @@
$('table#livres > tbody form').remove();
$('#new-book a').show();
$('table#livres tbody').prepend('<%= j render @livre %>');

@ -0,0 +1,3 @@
$('.delete').bind('ajax:success', function() {
$(this).closest('tr').fadeOut();
});

@ -1,35 +1,26 @@
<h1>Tableau de mes livres</h1>
<% if @livres.size > 0 %>
<table id="livres" class="table table-bordered">
<thead class="thead-dark">
<tr>
<th>#</th>
<th>Titre</th>
<th>Auteur</th>
<th>Synopsis</th>
<th>Style</th>
<th>ISBN</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<% @livres.each do |livre| %>
<div class="table-responsive">
<table id="livres" class="table table-bordered">
<thead class="thead-dark">
<tr>
<td><%= livre.id %></td>
<td><%= livre.titre %></td>
<td><%= livre.auteur %></td>
<td><%= livre.synopsis[0..120] %></td>
<td><%= livre.style %></td>
<td><%= livre.isbn %></td>
<td><%= link_to 'Edit', edit_livre_path(livre) %></td>
<th>Titre</th>
<th>Auteur</th>
<th>Synopsis</th>
<th>Style</th>
<th>ISBN</th>
<th>Action</th>
</tr>
<% end %>
</tbody>
</table>
</thead>
<tbody>
<%= render @livres %>
</tbody>
</table>
</div>
<% end %>
<%= link_to 'Nouveau livre', new_livre_path %>
<div id="new-book">
<%= link_to 'Nouveau livre', new_livre_path, remote: true %>
</div>

@ -0,0 +1 @@
json.array! @livres, partial: "livres/livre", as: :livre

@ -0,0 +1 @@
$('#new-book a').hide().parent().append("<%= j render 'form', livre: @livre %>");

@ -0,0 +1,29 @@
<p id="notice"><%= notice %></p>
<p>
<strong>Titre :</strong>
<%= @livre.titre %>
</p>
<p>
<strong>Auteur :</strong>
<%= @livre.auteur %>
</p>
<p>
<strong>Synopsis :</strong>
<%= @livre.synopsis %>
</p>
<p>
<strong>Style :</strong>
<%= @livre.style %>
</p>
<p>
<strong>ISBN :</strong>
<%= @livre.isbn %>
</p>
<%= link_to 'Edit', edit_livre_path(@livre) %> |
<%= link_to 'Back', livres_path %>

@ -0,0 +1 @@
json.partial! "livres/livre", livre: @livre

@ -12,3 +12,4 @@ Rails.application.config.assets.paths << Rails.root.join('node_modules')
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
# Rails.application.config.assets.precompile += %w( admin.js admin.css )
Rails.application.config.assets.precompile += %w( livres.js )

@ -1,6 +1,6 @@
Rails.application.routes.draw do
get 'livres/index'
resources :emprunts
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
resources :livres
post '/livres/tabledit' => 'livres#tabledit'
end

@ -0,0 +1,10 @@
class CreateEmprunts < ActiveRecord::Migration[5.2]
def change
create_table :emprunts do |t|
t.integer :idlivre
t.integer :nombre
t.timestamps
end
end
end

@ -10,7 +10,14 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_02_03_130314) do
ActiveRecord::Schema.define(version: 2020_02_17_133444) do
create_table "emprunts", force: :cascade do |t|
t.integer "idlivre"
t.integer "nombre"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "livres", force: :cascade do |t|
t.string "titre"

@ -0,0 +1,48 @@
require 'test_helper'
class EmpruntsControllerTest < ActionDispatch::IntegrationTest
setup do
@emprunt = emprunts(:one)
end
test "should get index" do
get emprunts_url
assert_response :success
end
test "should get new" do
get new_emprunt_url
assert_response :success
end
test "should create emprunt" do
assert_difference('Emprunt.count') do
post emprunts_url, params: { emprunt: { idlivre: @emprunt.idlivre, nombre: @emprunt.nombre } }
end
assert_redirected_to emprunt_url(Emprunt.last)
end
test "should show emprunt" do
get emprunt_url(@emprunt)
assert_response :success
end
test "should get edit" do
get edit_emprunt_url(@emprunt)
assert_response :success
end
test "should update emprunt" do
patch emprunt_url(@emprunt), params: { emprunt: { idlivre: @emprunt.idlivre, nombre: @emprunt.nombre } }
assert_redirected_to emprunt_url(@emprunt)
end
test "should destroy emprunt" do
assert_difference('Emprunt.count', -1) do
delete emprunt_url(@emprunt)
end
assert_redirected_to emprunts_url
end
end

@ -0,0 +1,9 @@
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
idlivre: 1
nombre: 1
two:
idlivre: 1
nombre: 1

@ -0,0 +1,7 @@
require 'test_helper'
class EmpruntTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end

@ -0,0 +1,45 @@
require "application_system_test_case"
class EmpruntsTest < ApplicationSystemTestCase
setup do
@emprunt = emprunts(:one)
end
test "visiting the index" do
visit emprunts_url
assert_selector "h1", text: "Emprunts"
end
test "creating a Emprunt" do
visit emprunts_url
click_on "New Emprunt"
fill_in "Idlivre", with: @emprunt.idlivre
fill_in "Nombre", with: @emprunt.nombre
click_on "Create Emprunt"
assert_text "Emprunt was successfully created"
click_on "Back"
end
test "updating a Emprunt" do
visit emprunts_url