So first I am a absolute beginner, so sorry if my code looks horrible. I am working on a booking platform where users can book seats in a bus and exchange them with each other if they don't need them. Exchanging them is the only way to get rid of a seat booking, they can't simply cancel/delete it.
If a user doesn't need their Booking
then he/she can create a Angebot
(offer) on a marketplace/list for that given Booking
. Other users can request it with a Anfrage
(request). This Anfrage
(request) contains alternative data from the requesting user which contains the same columns as Booking
. Now I am trying to replace the data in one Booking
with data from a Anfrage
(request). This is achieved when the user that created the Angebot
(offer) and own the Booking
accepts one of the Anfrage
(request).
def update_booking_durch_anfrage
@angebot = Angebot.where(id: anfrage_params[:angebot_id]).first
@booking = Booking.find_by_id(@angebot)
@gleiche_anfragen = Anfrage.find_by_id(@angebot)
respond_to do |format|
if @booking.update(
user_id: @angebot.user_id,
vorname: @angebot.vorname,
nachname: @angebot.nachname,
email: @angebot.email,
handynummer: @angebot.handynummer
)
@gleiche_anfragen.destroy
@angebot.destroy
format.html { flash[:notice] = 'Die Buchung wurde erfolgreich auf dich übertragen!' and redirect_to action: "index" }
format.json { render :show, status: :ok, location: @booking }
else
format.html { render :edit }
format.json { render json: @booking.errors, status: :unprocessable_entity }
end
end
end
Here are the schema.rb
and the relations between the models.
create_table "anfrages", force: :cascade do |t|
t.integer "angebot_id"
t.integer "user_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "vorname"
t.string "nachname"
t.string "handynummer"
t.string "email"
t.index ["angebot_id"], name: "index_anfrages_on_angebot_id"
t.index ["user_id"], name: "index_anfrages_on_user_id"
end
create_table "angebots", force: :cascade do |t|
t.integer "booking_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["booking_id"], name: "index_angebots_on_booking_id"
end
create_table "bookings", force: :cascade do |t|
t.integer "bus_id"
t.integer "user_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "vorname"
t.string "nachname"
t.string "handynummer"
t.string "email"
t.index ["bus_id"], name: "index_bookings_on_bus_id"
t.index ["user_id"], name: "index_bookings_on_user_id"
end
class Angebot < ApplicationRecord
attr_accessor :user_id, :vorname, :nachname, :email, :handynummer
belongs_to :booking
has_many :anfrages
end
class Anfrage < ApplicationRecord
belongs_to :angebot
belongs_to :user
end
class Booking < ApplicationRecord
belongs_to :bus
belongs_to :user
has_one :angebot
end
But right now this method doesn't do what it is supposed to. It simply redirects me to the edit.html.erb
view from Anfrages
without doing anything to the data. I think it has to do with the way rails handles updates and the corresponding forms but I have no clue how to change that.
The other thing is that I am no sure if the controller is the right place for this kind of logic and maybe it belongs into the model.
Thanks in advance for your help and time.
Looking at your code, your controller's logic goes like
if @booking.update(...)
else
...
format.html { render :edit }
end
So what is happening is updating the booking isn't working, returning false
and redirecting you to the edit view. You can get more insight into exactly why updating that Booking is failing by instead calling @booking.update!(...)
which will raise an error instead of just returning false if the booking does not update.
Additionally, you may be able to save yourself some headache by defining methods on your models to list those attributes. Something like
class Angebot
def booking_attributes
%i[user_id vorname nachname email handynummer].map do |a|
[a, send(a)]
end.to_h
end
end
# Controller
@booking.update(@angebot.booking_attributes)
So I figured it out what was wrong. First the link_to
method in my view was sending the wrong params so I set it up correctly. Than update_booking_durch_anfrage
method wasn't able to fetch this data correctly because of all the relations. I now created this 4 step data fetch approach that seems to work. And the last thing is as you can see that the data which I tried to replace wasn't stored in Angebot
but in Anfrage
...
So here's the solution that fetches the right Booking
and updates it with data from the correct Anfrage
. It's important that the link in the view uses PUT
, because you want to update the data. Big thanks also to Justin for his booking_attributes
method which made it a lot easier.
<%= link_to 'Tauschanfrage annehmen', {:controller => "angebots", :action => "update_booking_durch_anfrage", :id => anfrage.id, :angebot_id => anfrage.angebot_id }, :method => :put, data: { confirm: 'Bist du dir sicher, dass du die Tauschanfrage annehmen möchtest?'}, class: 'btn btn-outline-primary' %>
As you can see it sends the right parameters which are needed {:controller => "angebots", :action => "update_booking_durch_anfrage", :id => anfrage.id, :angebot_id => anfrage.angebot_id }
Next the method in the controller fetches the right data with a lot of .where
methods.
def update_booking_durch_anfrage
@anfrage = Anfrage.where(id: anfrage_params[:id]).first
@angebot = Angebot.where(id: anfrage_params[:angebot_id]).first
@booking = Booking.where(id: @angebot.booking_id).first
@gleiche_anfragen = Anfrage.where(angebot_id: anfrage_params[:angebot_id]).first
respond_to do |format|
if @booking.update!(@anfrage.booking_attributes)
@gleiche_anfragen.destroy
@angebot.destroy
format.html { flash[:notice] = 'Die Buchung wurde erfolgreich übertragen!' and redirect_to action: "index" }
else
format.html { flash[:notice] = 'Irgendwas ist schief gegangen...' and redirect_to action: "index" }
end
end
end
class Anfrage < ApplicationRecord
belongs_to :angebot
belongs_to :user
validates :vorname, presence: true
validates :nachname, presence: true
validates :email, presence: true, :format => /\A[^@\s]+@[^@\s]+\z/
def booking_attributes
%i[user_id vorname nachname email handynummer].map do |a|
[a, send(a)]
end.to_h
end
end
class Booking < ApplicationRecord
belongs_to :bus
belongs_to :user
has_one :angebot, dependent: :destroy
validates :vorname, presence: true
validates :nachname, presence: true
validates :email, presence: true, :format => /\A[^@\s]+@[^@\s]+\z/
end
It saves the data after validation in the Model and everything works smoothly. I am sure that's a lot of spaghetti code but it gets the job done...
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.