Rails Models Design Decision

2019-08-01 12:32发布

So to simplify what I have, there are 3 main models in my application; city, restaurant and recipe. A city has many restaurants and a restaurant has many recipes. Every city has a page that lists the restaurants in that city and similarly every restaurant page has recipes listed in their page. There is also a "Add new restaurant" button in my city page, when the user clicks on this the user is taken to the new restaurant page with the following link:

<%= link_to 'Add New Restaurant', new_restaurant_path %>

But this page is a generic page that the user can add a restaurant to any city, how do i modify my design so that, that new restaurant form would only add a new restaurant to that city.

Edit: Thanks for the answers. So this is my restaurant create method right now.. Because new_restaurant_path is a form and it has other params than just a city. So i understand that I can figure out the city of my restaurant by doing @city = City.find(params[:city]) but how do I add this to the rest of the params in this line @restaurant = Restaurant.new(params[:restaurant])

def create
    @restaurant = Restaurant.new(params[:restaurant])

  end

3条回答
三岁会撩人
2楼-- · 2019-08-01 13:05

You might also benefit from one of Ryan Bates' nice videos on nested resources http://railscasts.com/episodes/139-nested-resources

查看更多
可以哭但决不认输i
3楼-- · 2019-08-01 13:09

With routes

You can create a route like this:

/cities/:city_id/restaurants/new

with:

resources :city do
  resources :restaurants
end

and the helper:

<%= link_to 'Add New Restaurant', new_city_restaurant_path(city) %>

With params in helper

Or you can pass a parameter in your current route helper and handle it in your controller:

<%= link_to 'Add New Restaurant', new_restaurant_path(city_id: city.id) %>

This will make a use this URL:

/restaurants/new?city_id=123

For both approaches, the controller

and in the controller:

def create
  city = City.find(params[:city_id])
  @restaurant = city.restaurants.build params[:restaurant]
  if @restaurant.save
    ...
end
查看更多
虎瘦雄心在
4楼-- · 2019-08-01 13:20

2 ways to accomplish this

1) Add a nested route to your cities path for restaurants then use the new_city_restaurants_path(@city.id) You would have to either create folders and views inside your cities folder or move all your restaurants folder inside the cities folder. There would also be a few other bits and piees that would need tidying up such as controllers and helpers and this may not suit.

So possibly simpler

2) add the city id to the link_to as a parameter and change the new action in the restaurants controller to check for the presence of the city id and take appropriate action so you might end up with something like this

<%= link_to 'Add New Restaurant', new_restaurant_path(:city => @city.id) %>

Then in your controller's new action add the check

  def new
    if params[:city]
      #find the city and build a new restaurant object
      city = City.find(params[:city_id])
      @restaurant = city.restaurants.build params[:restaurant]
    else
      # just create a new restaurant object as normal
      @restaurant = Restaurant.new  
    end
    # ...Rest of action
  end

edit in response to comments

Because you have built the restaurant against the city object the city id will be assigned to the restaurant object the way to deal with this depends on the code in the new.html.erb template.

If you have a city selection box then use the city id from the @restaurant object to pre select the city. That way there is no need to change any code in the params hash or the controller create action. It's difficult to advise further as I don't have your new.html.erb code Your accepted answer deals with this in the wrong way IMO.

查看更多
登录 后发表回答