Je m'entraîne sur des rails et j'ai des moments difficiles avec des ressources imbriquées.
J'ai des auteurs, des livres et des genres dans ma BD. J'ai ajouté une ressource imbriquée sur routes.rb :
Started POST "/authors/11/books" for 127.0.0.1 at 2019-01-10 13:37:21 +0300
Processing by BooksController#create as HTML
Parameters: {"utf8"=>"â", "authenticity_token"=>"SHORTENED_THIS==", "book"=>{"name"=>"Shiny Tales", "release"=>"2011", "genre_id"=>"1"}, "commit"=>"Create Book", "author_id"=>"11"}
(0.1ms) BEGIN
â³ app/controllers/books_controller.rb:29
Genre Load (0.2ms) SELECT `genres`.* FROM `genres` WHERE `genres`.`id` = 1 LIMIT 1
â³ app/controllers/books_controller.rb:29
(0.2ms) ROLLBACK
â³ app/controllers/books_controller.rb:29
(0.1ms) BEGIN
â³ app/controllers/books_controller.rb:31
(0.1ms) ROLLBACK
â³ app/controllers/books_controller.rb:31
Rendering books/new.html.erb within layouts/application
Rendered books/_form.html.erb (1.8ms)
Rendered books/new.html.erb within layouts/application (2.8ms)
Completed 200 OK in 32ms (Views: 20.0ms | ActiveRecord: 1.3ms)
Je peux voir la nouvelle route par rake routes : new_author_book .
J'ai ajouté un lien vers l'auteur - show.html.erb :
books_controller.rb :
def new
@author = Author.find(params[:author_id])
@book = @author.books.new
end
def create
@book = Book.create(book_params)
respond_to do |format|
if @book.save
format.html { redirect_to @book, notice: 'Book was successfully created.' }
format.json { render :show, status: :created, location: @book }
else
format.html { render :new }
format.json { render json: @book.errors, status: :unprocessable_entity }
end
end
end
Donc ce lien me redirige vers http: // localhost: 3000 / auteurs / [author_id] / books / new
Je peux voir correctement author_id en utilisant params [: author_id] dans new.html.erb (Livres)
J'ai essayé de trouver cet auteur dans le books_controller en utilisant:
def new
@book = Book.new
end
Mais une erreur se produit car Impossible de trouver l'auteur sans identifiant
J'ai utilisé l'échafaudage pour créer ces tables et relations.
Voici mon _form.html.erb partial (Books)
<%= form_with(model: book, local: true) do |form| %>
<% if book.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(book.errors.count, "error") %> prohibited this book from being saved:</h2>
<ul>
<% book.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :release %>
<%= form.text_field :release %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Voici les books_contollers#new,
def create @author = Author.find(params[:author_id]) @book = @author.book.create(book_params) end
DERNIER STATUT DE L'APPLICATION:
<%= link_to "Add a Book to This Author" , new_author_book_path(@author) %>
Réponse du serveur:
resources :authors do
resources :books
end
J'ai essayé de suivre Rails Guides ajout d'un deuxième modèle mais je pense que c'est un peu différent.
Je ne veux pas faire de sélection d'auteur ou quelque chose comme ça dans cette situation parce que j'ai déjà sélectionné un auteur dans l'auteur- show.html .erb
3 Réponses :
Il me semble qu'un peu de mélange est nécessaire ici. Je pense que vos actions new et create sont dans le mauvais sens.
params [: author_id] est disponible pour votre nouvelle action, qui devrait ressembler à quelque chose comme:
def create @author = Author.find(params[:author_id]) @book = @author.books.create(book_params) end
Et puis create devrait être:
<%= form_with(model: [@author, @book]) do |form| %>
Vous pourriez bien avoir besoin d'un champ dans votre formulaire livre pour author_id , bien que je ne me souvienne pas du haut de ma tête si cela est nécessaire. Par exemple:
def book_params params.require(:book).permit(:author_id, ... the rest of your attributes) end
Si vous procédez ainsi, assurez-vous que author_id est sur la liste blanche dans les paramètres des books_controllers : p >
<%= form.hidden_field :author_id, book.author_id %>
De plus, votre formulaire doit être mis à jour pour pointer vers la ressource imbriquée ( docs ici ), qui fournira paramètres [: author_id] à votre action create , ce qui signifie que vous pouvez le conserver tel quel. Vous passez simplement un tableau au générateur de formulaire, c'est-à-dire
def create @book = Book.create(book_params) end
Cela configure le formulaire pour qu'il atteigne l'URL imbriquée avec le paramètre author_id en place comme souhaité.
Si vous suivez cette approche, votre action create devrait ressembler à ceci:
def new @author = Author.find(params[:author_id]) @book = @author.books.new end
J'espère qu'il y a quelque chose là-dedans qui aide - dites-moi comment vous vous en sortez.
Merci mais quel est le build_book? Il dit "méthode non définie` build_book 'pour #
Désolé, c'était un peu une hypothèse de ma part: pour une relation appartient_to , Rails ajoute un méthode build_association , et je pensais que c'était ce que vous utilisiez. Vous pouvez initialiser le livre comme vous le souhaitez (comme @book = @ author.book.new ) :)
Avez-vous réussi à faire fonctionner @Zogimu? Cela vous a-t-il aidé du tout?
Désolé d'être en retard. J'utilise appartient_to mais build_book n'a pas fonctionné. J'ai essayé "@book = @ author.books.new" mais il dit toujours que l'auteur doit exister.
Merci pour la mise à jour @Zogimu, et pas de soucis sur le délai :) J'ai mis à jour ma réponse avec deux points: la mise à jour des paramètres autorisés pour la première option, et l'action create pour cette dernière. J'irais personnellement avec ce dernier. Heureux de tenter le coup? Faites-moi savoir vos commentaires / questions!
author_id est déjà sur la liste blanche par défaut. Lorsque j'ajoute le "@author = Author.find (params [: id])" pour créer une action, des erreurs se produisent "Impossible de trouver l'auteur sans ID". Permettez-moi d'ajouter les réponses du serveur au message principal. Apprécié pour votre aide.
C'est mon mauvais @Zogimu - ça aurait dû être @author = Author.find (params [: author_id]) , désolé. Essayez cela dans l'action create et nous devrions avoir ce déclenchement :) BTW, votre commentaire sur le fait de ne pas vouloir de sélection d'auteur dans plusieurs actions - ne vous inquiétez pas pour cela, c'est standard et assez nécessaire. Il est en fait assez conventionnel d'avoir un before_action pour gérer cela , mais c'est pour une autre étape du guide, j'en suis sûr!
toujours la même erreur dans l'action de création. "Impossible de trouver l'auteur sans identifiant". Avez-vous vu les réponses du serveur? Je ne comprends pas, il y a un paramètre author_id et il dit que l'auteur est nécessaire.
D'accord, c'est très étrange. Ce message d'erreur suggère que params [: author_id] renvoie nil malgré ce que nous voyons, bien qu'il serait également intéressant de vérifier qu'un auteur avec l'ID 11 existe bien. Peut-être que met "ID from params: # {params [: author_id]}"; met "Author: # {Author.find_by_id (params [: author_id])}" au début de votre action create et vérifiez la sortie @Zogimu?
Je l'ai ajouté pour créer une action mais je ne mets rien à voir ou à serveur à la fois. J'ai utilisé emma et il y a un auteur avec un ID 11.
1: La première méthode la plus propre serait:
def create @book = Book.create(book_params) end
Cela vous amènera à créer / mettre à jour le chemin du livre avec author_id. Et dans votre contrôleur:
<%= form.hidden_field :author_id, params[:author_id] %>
2: Sinon, vous pouvez ajouter un hidden_field dans votre formulaire existant comme:
def create @author = Author.find(params[:author_id]) @book = @author.book.create(book_params) end
Merci. L'ajout de hidden_field est-il sûr?
L ' id dans l'URL est-il sûr? Si quelqu'un peut changer le hidden_field, il peut également changer l'identifiant dans l'URL. Mais je préférerais la première solution
Existe-t-il un moyen d'ajouter des livres "en toute sécurité" avec le bouton placé sous la page # show des auteurs?
Si je ne me trompe pas, vous vous inquiétez de la mise à jour des livres de User1 par User1. Droit? Vous pouvez utiliser la gemme cancancan pour vous assurer que
Ou bien si vous utilisez une gemme authentification et que l'auteur est l'utilisateur connecté. Vous pouvez utiliser l'utilisateur de la session en cours pour mettre à jour uniquement ses livres. Il / Elle ne pourra pas mettre à jour d'autres livres
Non, je n'utilise pas. Je pratique les rails. J'ai essayé accepte_nested_attributes dans la même page et select_tags pour enregistrer et je l'ai fait mais je n'ai pas pu faire celui-ci (ressources imbriquées). Merci encore.
Si votre problème est résolu par ma réponse, veuillez l'accepter et aider les autres également
C'est très similaire à ma réponse @ G.B. J'ai remarqué qu'un autre a suivi l'un des miens plus tôt dans la journée. Y a-t-il une raison à cela?
@SRack s'il vous plaît voir les commentaires sur la question
Et eux @ G.B?
Enfin, j'ai résolu le problème en créant une fonction personnalisée en tant que set_author dans books_controller
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update, :destroy]
before_action :set_author , only: [:new,:create]
def new
@book = Book.new
end
def create
@book = Book.create(book_params)
@book.author_id = @author.id
end
private
# Use callbacks to share common setup or constraints between actions.
def set_book
@book = Book.find(params[:id])
end
def set_author
@author = Author.find(params[:author_id])
end
end
Dans l'action de création, @book = Author.find (params [: author_id]). Books.create (book_params) pourrait être mieux au lieu de créer une nouvelle méthode set_author .
@ray Je ne peux pas essayer ceci maintenant mais chaque fois que je veux utiliser les paramètres [: author_id] dans l'action de création, c'était nul.
@ray ok je l'ai essayé. Il indique "Impossible de trouver l'auteur sans identifiant"
Pouvez-vous m'expliquer, si vous n'obtenez pas les paramètres [: author_id] dans l'action de création, comment avez-vous obtenu la même chose dans le filtre before_action set_author . Vos paramètres doivent être les mêmes pour set_author et create , n'est-ce pas?
@ray je ne sais pas. Je peux l'utiliser sur une nouvelle action mais je ne peux pas l'utiliser lors de la création.
@ ray a raison - si votre code fonctionne, les params [: author_id] dans l'action de création devraient également l'être. Impair. Heureux que vous ayez une solution :)
Veuillez afficher le
nouveaucode d'action@Vasfed ajouté au message principal.
ceci est dû au fait que
author_idest présent dans lanouvelle actionmais n'a pas été soumis dans votre formulaire pourcréer une action@ G.B alors comment puis-je le soumettre?
Il y a plusieurs façons! Je dois les ajouter comme réponse (je ne peux pas les commenter à cause de leur longueur)