Browse Source

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

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

+ 1
- 0
Gemfile View File

@@ -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'



+ 3
- 0
Gemfile.lock View File

@@ -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)


+ 2
- 2
app/assets/javascripts/application.js View File

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

+ 3
- 0
app/assets/javascripts/emprunts.coffee View File

@@ -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/

+ 594
- 594
app/assets/javascripts/jquery.tabledit.js
File diff suppressed because it is too large
View File


+ 0
- 37
app/assets/javascripts/livres.coffee View File

@@ -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']]
}
});

+ 47
- 0
app/assets/javascripts/livres.js View File

@@ -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);
}
});

+ 613
- 0
app/assets/javascripts/rails.tabledit.js View File

@@ -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));


+ 2
- 2
app/assets/stylesheets/_mixin.sass View File

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

$link-color: #AF6D36
//$link-color: #AF6D36

+ 2
- 0
app/assets/stylesheets/application.sass View File

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

@import 'mixin'
@import 'bootstrap'
@import 'font-awesome'

+ 3
- 0
app/assets/stylesheets/emprunts.scss View File

@@ -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/

+ 1
- 0
app/assets/stylesheets/scaffolds.scss View File

@@ -0,0 +1 @@


+ 74
- 0
app/controllers/emprunts_controller.rb View File

@@ -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

+ 43
- 11
app/controllers/livres_controller.rb View File

@@ -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


+ 2
- 0
app/helpers/emprunts_helper.rb View File

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

+ 9
- 0
app/helpers/livres_helper.rb View File

@@ -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

+ 2
- 0
app/models/emprunt.rb View File

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

+ 2
- 0
app/views/emprunts/_emprunt.json.jbuilder View File

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

+ 27
- 0
app/views/emprunts/_form.html.erb View File

@@ -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 %>

+ 6
- 0
app/views/emprunts/edit.html.erb View File

@@ -0,0 +1,6 @@
<h1>Editing Emprunt</h1>

<%= render 'form', emprunt: @emprunt %>

<%= link_to 'Show', @emprunt %> |
<%= link_to 'Back', emprunts_path %>

+ 29
- 0
app/views/emprunts/index.html.erb View File

@@ -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 %>

+ 1
- 0
app/views/emprunts/index.json.jbuilder View File

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

+ 5
- 0
app/views/emprunts/new.html.erb View File

@@ -0,0 +1,5 @@
<h1>New Emprunt</h1>

<%= render 'form', emprunt: @emprunt %>

<%= link_to 'Back', emprunts_path %>

+ 14
- 0
app/views/emprunts/show.html.erb View File

@@ -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 %>

+ 1
- 0
app/views/emprunts/show.json.jbuilder View File

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

+ 1
- 0
app/views/layouts/application.html.erb View File

@@ -30,5 +30,6 @@
<%= yield %>

</main>
<%#= javascript_include_tag 'livres.js' %>
</body>
</html>

+ 5
- 10
app/views/livres/_form.html.erb View File

@@ -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 %>

+ 11
- 0
app/views/livres/_livre.html.erb View File

@@ -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>

+ 2
- 0
app/views/livres/_livre.json.jbuilder View File

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

+ 3
- 0
app/views/livres/create.js.erb View File

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

+ 3
- 0
app/views/livres/destroy.js.erb View File

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

+ 18
- 27
app/views/livres/index.html.erb View File

@@ -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>

+ 1
- 0
app/views/livres/index.json.jbuilder View File

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

+ 1
- 0
app/views/livres/new.js.erb View File

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

+ 29
- 0
app/views/livres/show.html.erb View File

@@ -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 %>

+ 1
- 0
app/views/livres/show.json.jbuilder View File

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

+ 1
- 0
config/initializers/assets.rb View File

@@ -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 )

+ 2
- 2
config/routes.rb View File

@@ -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

+ 10
- 0
db/migrate/20200217133444_create_emprunts.rb View File

@@ -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

+ 8
- 1
db/schema.rb View File

@@ -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"


+ 48
- 0
test/controllers/emprunts_controller_test.rb View File

@@ -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

+ 9
- 0
test/fixtures/emprunts.yml View File

@@ -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

+ 7
- 0
test/models/emprunt_test.rb View File

@@ -0,0 +1,7 @@
require 'test_helper'

class EmpruntTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end

+ 45
- 0
test/system/emprunts_test.rb View File

@@ -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
click_on "Edit", match: :first

fill_in "Idlivre", with: @emprunt.idlivre
fill_in "Nombre", with: @emprunt.nombre
click_on "Update Emprunt"

assert_text "Emprunt was successfully updated"
click_on "Back"
end

test "destroying a Emprunt" do
visit emprunts_url
page.accept_confirm do
click_on "Destroy", match: :first
end

assert_text "Emprunt was successfully destroyed"
end
end

Loading…
Cancel
Save