I am beginner with Ruby on Rails, and I am trying to build a little app that permit people to order a pastrie from a cooker, for a day chosen.
When they select the pastrie using a checkbox, I would like that the selected pastrie was saved as pastrie_id in the table fight but instead, I have an issue :
Validation failed: Pastrie must exist.
UPDATE this is working :
<%= f.association :pastrie, as: :check_boxes, label: 'Pastrie' %>
I still have an issue, the saving params are not good I have :
"fight"=>{"pastrie_id"=>["", "1"]},
I tried a lot of solutions found on stackoverflow but nothing seems to work.
I am using Rails 5.2.3
So, this is my schema :
ActiveRecord::Schema.define(version: 2019_06_06_094318) do
create_table "cookers", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "pastrie"
end
create_table "events", force: :cascade do |t|
t.datetime "date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "fights", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "pastrie_id"
t.integer "event_id"
t.integer "cooker_id"
t.index ["cooker_id"], name: "index_fights_on_cooker_id"
t.index ["event_id"], name: "index_fights_on_event_id"
t.index ["pastrie_id"], name: "index_fights_on_pastrie_id"
end
create_table "pastries", force: :cascade do |t|
t.string "pastrie_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
Here is my models :
class Event < ApplicationRecord
has_many :pastries, through: :fights
has_many :cookers, through: :fights
has_many :fights
end
class Fight < ApplicationRecord
belongs_to :pastrie
belongs_to :event
belongs_to :cooker, optional: true
end
class Pastrie < ApplicationRecord
has_many :fights
has_many :events, through: :fights
end
This is my controller. What I understand is : in order to create a Fight, I need an event_id and a pastrie_id (cooker_id is optional). So first, I create a new event (and so I have an event_id), and next, I need to connect a pastrie_id (existing in my seed) to my fight. But this is not working if I am doing that :
class FightsController < ApplicationController
def new
#fight = Fight.new
#event = Event.find(params[:event_id])
#pastries = Pastrie.all
end
def create
#fight = Fight.new(fight_params)
#event = Event.find(params[:event_id])
#fight.event = Event.find(params[:event_id])
#fight.pastrie_id = params[:fight][:pastrie_id]
#fight.save!
redirect_to root_path
end
def show
#events = Event.all
end
def index
#fights = Fight.all
fights_by_event = []
end
private
def fight_params
params.require(:fight).permit(:event_id, :pastrie_id, :cooker_id)
end
end
And my view when I am creating my "fight" :
<div class=margin-bottom>
<h2 class=text-center> Bonjour Linguini, quelles patisseries veux-tu choisir ?</h2>
</div>
<div class="container margin-bottom">
<%= simple_form_for [#event, #fight] do |f| %>
<% #pastries.each do |pastrie| %>
<%= f.label :pastrie_id do %>
<%= f.check_box :pastrie_id, as: :boolean, checked_value: true, unchecked_value: false %> <span><%= pastrie.pastrie_name%></span>
<% end %></br>
<% end %>
<%= f.submit "Valider", class: "btn btn-primary" %>
<% end %>
</div>
And this is my routes if you need this :
Rails.application.routes.draw do
root to: 'pages#home'
resources :events do
resources :fights, only: [:new, :show, :create]
end
resources :fights, only: [:index]
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
In your form change
<%= f.check_box :pastrie_id, as: :boolean, checked_value: true, unchecked_value: false %> <span><%= pastrie.pastrie_name%></span>
To
<%= f.check_box :pastrie_id, as: :boolean, checked_value: pastrie.id, unchecked_value: nil %> <span><%= pastrie.pastrie_name%></span>
In the first version you submit a param of {pastrie_id: true}, which obviously doesn't relate to a Pastry. The second version should submit the ID of the checked box (although if it belongs to only 1 pastry it might make more sense to make these radio buttons)
Related
Im currently trying to create a search form and everytime I try to send a request rails always report me the NoMethodError above. Below is my code.
controller
#search_cat = params['search_cat']
if #search_cat.present?
category_id = #search_cat['category_id']
#tasks = Task.where(user_id: current_user.id, category_id: category_id.to_i)
end
view
<%= simple_form_for :search_cat, url: tasks_index_path, method: "GET", html: { class: 'form-inline' } do |f| %>
<%= f.input :category_id, collection: current_user.categories,as: :select %>
<%= f.submit "Search", class: "btn btn-primary" %>
<% end %>
def tasks_params
params.require(:task).permit(:deadline_at,:title, :tags, :note, :is_done, :category_id, :user_id, {tag_ids: []})
end
edit:
class Task < ApplicationRecord
belongs_to :user, optional: true
belongs_to :category, optional: true
has_many :tag_associations, dependent: :destroy
has_many :tags, through: :tag_associations
end
schema
create_table "tasks", force: :cascade do |t|
t.datetime "deadline_at"
t.string "title"
t.string "note"
t.boolean "is_done"
t.integer "user_id"
t.integer "category_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["category_id"], name: "index_tasks_on_category_id"
t.index ["user_id"], name: "index_tasks_on_user_id"
I basiclly just trying send the input from the search form to query controller.
enter image description here
My guess would be that you don't have a category reference set in your task table. I would double check your schema to make sure you have all the columns within your task table match your params that you are permitting in your controller. Also make sure you have your relationships set within your models between your task model and category model.
Any advice would be most appreciated.
Is it possible to retrieve the email address used by a user, posting a comment, in a list#show/show.html.erb view? Without adding another column "email" to my Comments model?
The best I can do is retrieve the user_id, which is not that helpful.
<% #list.comments.each do |comment| %>
<p><%= comment.body%></p>
<p><%= comment.user_id %>
<% end %>
Comment.rb
class Comment < ApplicationRecord
belongs_to :list, optional: true
belongs_to :user
Comments Table
create_table "comments", force: :cascade do |t|
t.text "body"
t.bigint "list_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "user_id"
t.index ["list_id"], name: "index_comments_on_list_id"
t.index ["user_id"], name: "index_comments_on_user_id"
end
List controller#show
def show
#list = List.find(params[:id])
#current_user = current_user.id
end
Use Module#delegate from ActiveSupport:
class Comment < ApplicationRecord
belongs_to :list, optional: true
belongs_to :user
delegate :email, to: :user
end
<% #list.comments.each do |comment| %>
<p><%= comment.body%></p>
<p><%= comment.user_id %>
<p><%= comment.email %>
<% end %>
And make sure you use .includes or .eager_load in the controller to avoid a N+1 query:
def show
#list = List.includes(comments: :user).find(params[:id])
#current_user = current_user.id
end
I'm a rails noob that's tryin to do something in his app.
My problem is:
I have a Corso model, a Libro model and an Annuncio model. Corso has_many Libro, Libro has_many Annuncio, Annuncio belongs_to Libro and Libro belongs_to Corso. I want a form where the user can create a Libro (that MUST be associated to a Corso) and meanwhile an Annuncio of that Libro must be created. I'm literally freaking out, I saw hundreds of discussions but nothing solved my problem. Every time I change something I get some different errors.
My focus is:
- how to pass the corso_id (I mean, the objects Corso are already defined in the db) to the new Libro when I submit the form;
-I don't see why a Libro object is created (all fields nil) but an Annuncio object doesn't. It seems like the code #libro.annuncios.build in LibroController/new is useless.
I hope you will help me to get this form working.
LibroController:
class LibroController < ApplicationController
def new
#corso = Corso.find(params[:corso_id])
#libro = #corso.libros.build
#libro.annuncios.build
end
def create
#corso = Corso.find(params[:corso_id])
#libro = #corso.libros.build(libro_params)
if #libro.save
redirect_to #libro
else
redirect_to root_path
end
end
def show
#libro = Libro.find(params[:id])
end
def index
end
private
def libro_params
params.require(:libro).permit(:titolo, :autori, :casa_editrice, :edizione, :anno_pubblicazione, :ISBN, :immagine, :corso_id, annuncios_attributes[:prezzo, :note])
end
end
AnnuncioController:
class AnnuncioController < ApplicationController
def new
#annuncio = Annuncio.new
end
def create
#libro = Libro.find(params[:libro_id])
#annuncio = #libro.annuncio.build(annuncio_params)
if #annuncio.save
redirect_to #libro
else
redirect_to root_path
end
end
private
def annuncio_params
params.require(:annuncio).permit(:prezzo, :note)
end
end
Libro Model:
class Libro < ApplicationRecord
belongs_to :corso, inverse_of: :libros
has_many :annuncios, inverse_of: :libro
accepts_nested_attributes_for :annuncios
end
Annuncio Model:
class Annuncio < ApplicationRecord
belongs_to :utente, inverse_of: :annuncios
belongs_to :libro, optional: true, inverse_of: :annuncios
end
Corso Model:
class Corso < ApplicationRecord
belongs_to :facolta
has_many :libros
validates :nome, uniqueness: true
end
routes.rb (a little messed up)
Rails.application.routes.draw do
get 'facolta/new'
get 'sessions/create'
get 'sessions/destroy'
get 'users/new'
get 'corso/index'
get 'auth/:provider/callback', to: 'sessions#create'
get 'auth/failure', to: redirect('/')
get 'signout', to: 'sessions#destroy', as: 'signout'
resources :sessions, only: [:create, :destroy]
resource :home, only: [:show]
root 'facolta#index'
get 'corso_new' => 'corso#new'
get 'libro_new' => 'libro#new'
get 'about_us' => 'static_pages#about_us'
get 'faq' => 'static_pages#faq'
resources :facolta do
resources :corso
end
resources :corsos, shallow: true do
resources :libro
end
resources :libros do
resources :annuncio
end
resources :user do
resources :annuncio
end
end
views/libro/new
<h1>FORM DI REGISTRAZIONE HERE</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for([#corso, #libro]) do |libro| %>
<p>
<%= libro.label :titolo %>
<%= libro.text_field :titolo %>
</p>
<p>
<%= libro.label :autori %>
<%= libro.text_field :autori %>
</p>
<p>
<%= libro.label :casa_editrice %>
<%= libro.text_field :casa_editrice %>
</p>
<p>
<%= libro.label :edizione %>
<%= libro.text_field :edizione %>
</p>
<p>
<%= libro.label :anno_pubblicazione %>
<%= libro.text_field :anno_pubblicazione %>
</p>
<p>
<%= libro.label :ISBN %>
<%= libro.text_field :ISBN %>
</p>
<p>
<%= libro.label :immagine %>
<%= libro.text_field :immagine %>
</p>
<%= libro.fields_for :annuncios do |annuncio| %>
<p>
<%= annuncio.label :prezzo %>
<%= annuncio.text_field :prezzo %>
</p>
<p>
<%= annuncio.label :note %>
<%= annuncio.text_field :note %>
</p>
<% end %>
<%= libro.hidden_field :corso_id, value: params[:post_id]%>
<%= libro.submit "Inserisci il libro", class: "btn btn-primary" %>
<% end %>
</div>
</div>
schema.rb
create_table "annuncios", force: :cascade do |t|
t.integer "user_id"
t.integer "libro_id"
t.string "prezzo"
t.text "note"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["libro_id"], name: "index_annuncios_on_libro_id"
t.index ["user_id"], name: "index_annuncios_on_user_id"
end
create_table "corsos", force: :cascade do |t|
t.string "nome"
t.integer "facolta_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["facolta_id"], name: "index_corsos_on_facolta_id"
end
create_table "facolta", force: :cascade do |t|
t.string "nome"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "libros", force: :cascade do |t|
t.string "titolo"
t.string "autori"
t.string "casa_editrice"
t.string "edizione"
t.string "anno_pubblicazione"
t.string "ISBN"
t.string "immagine"
t.integer "corso_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["corso_id"], name: "index_libros_on_corso_id"
end
create_table "users", force: :cascade do |t|
t.string "provider"
t.string "uid"
t.string "name"
t.string "oauth_token"
t.datetime "oauth_expires_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email"
end
EDIT: edited with #arieljuod advices
You don't need to merge the corso_id here: #libro = #corso.libros.build(libro_params.merge({corso_id: #corso.id})). ActiveRecord already sets the corso_id since you are doing #corso.libros.build(...).
You also don't need that hidden_field with the Corso id since you already have that from the URL.
You may want to do #libro = #corso.libros.build on your new action too.
And finally, I think this is the main problem: this is wrong belongs_to :corso, inverse_of: :corsos, it should be inverse_of: :libros
Fix the other things I point out too to clean up your code.
EDIT:
to add a select do something like this:
= libro.select :corso_id, options_from_collection_for_select(Corso.all, :id, :name)
I'm trying to build a workout application where you submit a workout that consists of several exercises in rails. I was trying to create a "new" workout view where you can submit a new workout along with nested exercises but my "new" view is only showing the workout form fields, but not the exercise form fields. Btw I'm using Ruby 2.3 and Rails 5.0. Can anyone see what I'm doing wrong?
Workout Model (workout.rb)
class Workout < ActiveRecord::Base
has_many :exercises, :dependent => :destroy
accepts_nested_attributes_for :exercises
end
Exercise Model (exercise.rb)
class Exercise < ActiveRecord::Base
belongs_to :workout
end
Workouts Controller (workouts_controller.rb)
class WorkoutsController < ApplicationController
def new
#workout = Workout.new
#workout.exercises.build
end
end
New Workout View (views\workouts\new.html.erb)
<h1>Create New Workout</h1>
<%= form_for(#workout) do |f| %>
<%= f.number_field :workout_length, :placeholder => "Workout length (minutes)" %> <br>
<%= f.text_field :workout_description, :placeholder => "Workout description" %> <br>
<% f.fields_for :exercises do |builder| %>
<p>
<%= builder.text_field :exercise_description %>
</p>
<% end %>
<%= f.submit "SUBMIT WORKOUT" %>
Schema (schema.rb)
ActiveRecord::Schema.define(version: 20161207040053) do
create_table "exercises", force: :cascade do |t|
t.string "exercise_description"
t.integer "workout_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["workout_id"], name: "index_exercises_on_workout_id"
end
create_table "workouts", force: :cascade do |t|
t.integer "workout_length"
t.string "workout_description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
I figured it out... I didn't set up the proper relationship between the exercise and workout model.
How to access customer's name from Customer table onto my Order's action view index. And vice versa.
I am getting this error:
NoMethodError in Customers#index.
Undefined method `order' for #Customer:0x24f4...
class Customer < ActiveRecord::Base
has_many :orders, foreign_key: "customer_id"
end
class Order < ActiveRecord::Base
belongs_to :customer
end
In my migration:
create_table "customers", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "orders", force: :cascade do |t|
t.integer "customer_id"
t.datetime "orderdate"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "orders", ["customer_id"], name: "index_orders_on_customer_id", using: :btree
end
In customer's index.html.erb
<% #customers.each do |customer| %>
<%= customer.name %>
<%= customer.order.orderdate %>
<% end %>
In orders's index.html.erb
<% #orders.each do |order| %>
<%= order.orderdate %>
<%= order.customer.name %>
<% end %>
you have has many relation with customer and order so
In customer's index.html.erb
<% #customers.each do |customer| %>
<%= customer.name %>
<!-- this will display customers all order and fetch first and then show that order's orderdate -->
<%= customer.orders.first.orderdate %>
<% end %>
Try a different approach to setting the relationships between your models in the migration:
t.belongs_to :customer, index: true
See http://guides.rubyonrails.org/association_basics.html#the-belongs-to-association