简体   繁体   中英

Handling different models in one form submission rails

I have been trying to build an app offering discounted vacation trips such that: (1) a user(travel agent) can compose a trip by combining hotels (hotel chains) and cities (2) a user(regular user) can review hotels and cities, s/he has already visited. (3) another user can evaluate how good the deal is with respect to the country and hotel the travel agent will have him/her stay.

The models look like this

class User < ActiveRecord::Base has_many :trips has_many :reviews end

class Trip < ActiveRecord::Base belongs_to :user belongs_to :hotel belongs_to :city end

class Hotel < ActiveRecord::Base belongs_to :city has_many :reviews, as: :reviewable end

class City < ActiveRecord::Base has_many :hotels has_many :reviews, as: :reviewabel end

class Review < ActiveRecord::Base belongs_to :user belongs_to :reviewable, polymorphic: true end

The problem is I can figure out how to create the controllers for Hotel and City because they are only created in the context of a makeshift trip. I checked the rails casts on nested forms and the use of accepts_nested_attributes_for but I can't seem to get it right.

Note: the reason why I separated the hotels and the cities is to be able to retrieve the reviews independently. Such that Say I enjoyed my stay at the Four Seasons in Toronto but not the one in NY. - because of the cities/hotels (=> accommodating the case where I didn't enjoy it because the hotel was crap and the one where I didn't because the city was)

Note 2: I understand it doesn't make much sense to seperate hotels and cities in this example - I made a mistake in self-appointing the tutorial. But the problem has been haunting me, what if it was an delivery order instead with entree/meal/dinner instead of hotels and cities, or restaurant chains and neighborhoods.

Any help is appreciated. Thank you

Edit

Edited after Settheline's comment.

I mean the create actions for cities and hotels only exist in the context of a Trip create action. Trip has 2 attributes: title & description: It's only then that I “log” the itinerary. Here's what my controllers look like to give you a better idea

class TripsController < ApplicationController
  before_action :signed_in_user

  def show
    @trip = Trip.find(params[:id])
  end

  def index
    @trips = current_user.Trip.all
  end


  def new
    @trip = Trip.new
  end

  def create
   # @trip = Trip.new(trip_params)
   @trip = current_user.trips.build(trip_params)
   if @trip.save
     flash[:success] = "Your trip was successfully published!"
     redirect_to @trip
   else
     render 'new'
   end
  end

  def edit
  end

  def update
   if @trip.update_attributes(trip_params)
     flash[:success] = "Trip was updated"
     redirect_to @trip
   else
     render 'edit'
   end
  end

  def destroy
   Trip.find(params[:id]).destroy
   flash[:success] = "trip was deleted. Thank you"
   redirect_to @user #root_url
  end

  private

     def trip_params
       params.require(:trip).permit(:title, :description)      
     end  
end

class CitiesController < ApplicationController
  before_action :signed_in_user

  def create
    @city = City.new(city_params)
    if @city.save
      # flash[:success] = ""
    else
      render 'new'
    end
  end

  # def destroy
  #  City.find(params[:id]).destroy
  #  flash[:success] = “City was deleted."
  #  redirect_to root_url 
  # end

   private

     def city_params
       params.require(:city).permit(:name, :province, :country)
     end

 end


class HotelsController < ApplicationController
  before_action :signed_in_user

  def create
    #similar to city
  end

  def destroy
    #similar to city
  end

  private

    def hotel_params
      params.require(:hotel).permit(:name, :address,
                                              :management_contact,
                                             :city_id)
    end
end

And here's the problem: I want to have/add create forms within the trip one in

sample_app/app/views/trips/new.html.erb

<% provide(:title, 'New Trip') %>
<h1>New Trip</h1>
<div class="row">
  <div class="span6 offset3">
    <%= form_for(@trip) do |f| %>
      <%= render 'shared/error_messages', object: f.object %>

      <%= f.text_field :title, placeholder: "Type in a title" %>
      <%= f.text_field :description, placeholder: "Any additional info." %>

      <%= f.submit "Publish", class: "btn btn-large btn-primary" %>
    <% end %>
  </div>
</div>

accepts_nested_attributes_for allows you to save attributes on associations. Although you do have associations in your models it doesn't necessarily mean that you need to use accepts_nested_attributes_for . It depends on how the code flows through your controllers.

Simple Example

For example, you would probably want to allow your users to view their trips and reviews. First you'll need a method to get the current user:

users_controller.rb

class ApplicationController < ActionController::Base
  def current_user
    @current_user ||= User.find(session[:user_id])
  end
end

This method will be inherited by all of your controllers and allow them to get the current user. (There are many solutions out there for getting the current user, this is definitely not a good solution but it is OK for demonstration purposes).

Trips & Reviews

Now you can create some controllers for the current user to view their trips and reviews:

trips_controller.rb

class TripsController < ApplicationController
  def index
    @trips = current_user.trips.all
  end
end

reviews_controller.rb

class ReviewsController < ApplicationController
  def index
    @reviews = current_user.reviews.all
  end
end

Now you have some controller actions displaying the trips/reviews for the current user. I think this example demonstrates how you can create your controllers and that accepts_nested_attributes_for is not necessarily required.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM