I'm getting the error from line #7 of my views when I'm trying to create a new room:
undefined method `rooms_path' for #<#<Class:0x007fb46b5db2a0>:0x007fb46b5d9ec8>
I'm a little confused about why am I getting this error. I have built a relationship between Room and Facility that each Facility has many Rooms. The Facility part works bug free, I've been able to create/edit/show facilities.
Views (views/rooms/new.html.erb)
<div class="panel panel-default">
<div class="panel-heading">
Create your beautiful room
</div>
<div class="panel-body">
<div class="container">
<%= form_for #room do |f| %>
<div class="form-group">
<label>Name</label>
<%=f.text_field :room_name, placeholder: "What is the name of the room?", class: "form-control", required: true%>
</div>
<div><%= f.submit "Create This Room", class: "btn btn-normal" %></div>
<%end%>
</div>
</div>
</div>
My Room model (models/room.rb):
class Room < ApplicationRecord
belongs_to :facility
validates :room_type, presence: true
validates :room_name, presence: true
end
My Facility model (models/facility.rb):
class Facility < ApplicationRecord
belongs_to :user
has_many :photos
has_many :rooms
validates :facility_name, presence: true
validates :address, presence: true
validates :license, presence: true
validates :phone, presence: true
def cover_photo(size)
if self.photos.length > 0
self.photos[0].image.url(size)
else
"blank.jpg"
end
end
end
My Rooms Controller(controllers/rooms_controller.rb)
class RoomsController < ApplicationController
before_action :set_room, except: [:index, :new, :create]
def index
#facility = Facility.find(params[:facility_id])
#rooms = #facility.rooms
end
def new
#facility = Facility.find(params[:facility_id])
#room = #facility.rooms.build
end
end
Routes (routes.rb)
Rails.application.routes.draw do
devise_for :users,
path: '',
path_names: {sign_in: 'login', sign_out: 'logout', edit: 'profile', sign_up: 'registration'},
controllers: {omniauth_callbacks: 'omniauth_callbacks', registrations: 'registrations'}
resources :users, only: [:show]
resources :facilities, except: [:edit] do
member do
get 'listing'
get 'pricing'
get 'features'
get 'services'
get 'types_care'
get 'photo_upload'
get 'room_upload'
end
resources :rooms, except: [:edit] do
member do
get 'listing'
get 'pricing'
get 'photo_upload'
end
end
resources :photos, only: [:create, :destroy]
end
end
Been stuck on this for a couple of days and would really appreciate the help :) Thanks so much in advance!
form_for generate url based on class of #room, it doesn't include outer resource. Thus, you have to tell Rails to do that explicitly using below statement:
<%= form_for [#room.facility, #room] do |f| %>
Choose any of the following for form_for instead of <%= form_for #room do |f| %> as your routes are nested
<%= form_for #room, url: [#room.facility, #room] do |f| %>
<%= form_for #room, url: [:facility, #room] do |f| %>
<%= form_for [#room.facility, #room] do |f| %>
<%= form_for [:facility, #room] do |f| %>
Here you can get more detail about form_for helper
Related
I have Categories (Parents) within which are listed Products (Children).
I want to be able to create a new Product directly from the navbar, anywhere in the app and then, during the creation, assign it to a Category.
However, I get the present error:
NoMethodError in Products#new
Showing /Users/istvanlazar/Mobily/app/views/products/new.html.erb where line #9 raised:
undefined method `products_path' for #<#<Class:0x00007febaa5aec98>:0x00007febae0f9e38>
Did you mean? product_show_path
## product_show_path is a custom controller that has nothing to do with this one,
enabling show and clean redirection from newest_products index bypassing categories nesting.
Extracted source (around line #9):
9 <%= form_for [#product] do |f| %>
10 <div class="form-styling">
11 <div>
12 <%= f.label :name %>
My App works as such:
Models
class Category < ApplicationRecord
has_many :products, inverse_of: :category
accepts_nested_attributes_for :products
validates :name, presence: true
end
class Product < ApplicationRecord
belongs_to :user, optional: true
belongs_to :category, inverse_of: :products
validates :category, presence: true
end
Routes
get 'products/new', to: 'products#new', as: 'new_product'
resources :categories, only: [:index, :show, :new, :edit] do
resources :products, only: [:index, :show, :edit]
# resources :products, only: [:index, :show, :new, :edit]
end
Controllers
class ProductsController < ApplicationController
before_action :set_category, except: :new
def index
#products = Product.all
#products = policy_scope(#category.products).order(created_at: :desc)
end
def show
#product = Product.find(params[:id])
end
def new
#product = Product.new
#product.user = current_user
end
def create
#product = Product.new(product_params)
#product.user = current_user
if #product.save!
redirect_to category_product_path(#category, #product), notice: "Product has been successfully added to our database"
else
render :new
end
end
private
def set_category
#category = Category.find(params[:category_id])
end
def product_params
params.require(:product).permit(:name, :price, :description, :category_id, :user, :id)
end
end
class CategoriesController < ApplicationController
def index
#categories = Category.all
end
def show
#category = Category.find(params[:id])
end
def new
# Non-existant created in seeds.rb
end
def create
# idem
end
def edit
# idem
end
def update
# idem
end
def destroy
# idem
end
private
def category_params
params.require(:category).permit(:name, :id)
end
end
Views
# In shared/navbar.html.erb:
<nav>
<ul>
<li>Some Link</li>
<li>Another Link</li>
<li><%= link_to "Create", new_product_path %></li>
</ul>
</nav>
# In products/new.html.erb:
<%= form_for [#product] do |f| %>
<div class="form-styling">
<div>
<%= f.label :name %>
<%= f.text_field :name, required: true, placeholder: "Enter product name" %>
<%= f.label :price %>
<%= f.number_field :price, required: true %>
</div>
<div>
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<div>
<%= f.label :category %>
<%= f.collection_select :category_id, Category.order(:name), :id, :name, {prompt: 'Select a Category'}, required: true %>
</div>
<div>
<%= f.submit %>
</div>
</div>
<% end %>
Do you have any idea of where it went wrong? Or is it impossible to Create a Child before assigning it to a Parent..?
Thanks in advance.
Best,
Ist
You haven't defined any route to handle your new product form's POST. You've defined the new_product path, but this arrangement is breaking Rails' conventions and you're not providing a work-around.
You could define another custom route, e.g. post 'products', to: 'products#create', as: 'create_new_product' and then set that in your form like form_for #product, url: create_new_product_path do |f|.
However, you should consider changing the structure so that product routes are not nested under categories. Think twice before breaking conventions this way.
Edit: I misread the intention, ignore this. Go with Jeremy Weather's answer.
Or is it impossible to Create a Child before assigning it to a Parent..?
With the way you have your relationships and validations set up: yes, it is. A Product requires a Category, through the validates :category, presence: true. And if you're on Rails 5+, the association will already be required by default (meaning that validates is actually redundant). Meaning if you try to create a Product without a Category, it will fail, and the Product will not be saved to the database.
With that constraint in place, here's what I recommend trying:
Remove the custom /products/new route
remove get 'products/new', to: 'products#new', as: 'new_product'
Add :new and :create routes to allow product creation nested under categories
Add :create and :new, to the :only array to the resources :products nested under resources :categories
Move the file views/products/new.html.erb to views/categories/products/new.html.erb (creating a new categories directory in views if necessary).
In that file, alter the form_for so that the form is POSTing to the nested :create route:
form_for [#category, #product] do |f|
Visit the URL /categories/[insert some Category ID here]/products/new, filling out some data, and see if that works.
Your routes.rb should look like this:
resources :categories, only: [:index, :show, :new, :edit] do
resources :products, only: [:index, :show, :new, :create, :edit]
end
I got a problem which I can't solve. I made two models; one model called Film is the parent model and another model called Review is the child model. I got validation conditions on the child model but it does not display on the view.
Film model
class Film < ApplicationRecord
has_many :reviews
validates_presence_of :filmtitle, presence: true
validates_presence_of :filmdescription, presence: true
validates_presence_of :filmdirector, presence: true
validates_presence_of :filmrating, presence: true
validates_presence_of :filmstarname, presence: true
end
Review model
class Review < ApplicationRecord
validates :rating, presence: true
validates :commenter, presence: true
validates :body, presence: true
belongs_to :film
end
Review Controller
class ReviewsController < ApplicationController
def create
#film = Film.find(params[:film_id])
#review = #film.reviews.create(review_params)
redirect_to film_path(#film)
end
private
def review_params
params.require(:review).permit(:commenter, :body, :rating)
end
end
Film show.html.erb
<% if #film.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#film.errors.count, "error") %></h2>
<ul>
<% #film.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= form_for([#film, Review.new]) do |f| %>
<p>
<%= f.label :commenter %><br>
<%= f.text_field :commenter, :placeholder => 'Your name' %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body, :placeholder => 'Your comment' %>
</p>
<p>
<%= f.label :rating %><br>
<%= f.select :rating, ['1 Star', '2 Stars', '3 Stars', '4 Stars', '5 Stars'] %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
Film Controller
class FilmsController < ApplicationController
before_action :set_film, only: [:show]
# GET /films
# GET /films.json
def index
#films = Film.all.paginate(page: params[:page], per_page: 30)
#reviews = Review.new
end
# GET /films/1
# GET /films/1.json
def show
end
# GET /films/new
def new
end
# GET /films/1/edit
def edit
end
# POST /films
# POST /films.json
def create
end
# PATCH/PUT /films/1
# PATCH/PUT /films/1.json
def update
end
# DELETE /films/1
# DELETE /films/1.json
def destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_film
#film = Film.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def film_params
params.require(:film).permit(:filmtitle, :filmdescription)
end
end
route.rb
Rails.application.routes.draw do
resources :films do
resources :reviews
end
resources :rentals
resources :buys
resources :admin
resources :adminrentals
resources :adminfilms
resources :logins
resources :admins_login
resources :games
get '/adminCool' => 'admins_login#index'
get '/adminlogin' => 'admins_sessions#new'
post '/adminlogin' => 'admins_sessions#create'
get '/adminlogout' => 'admins_sessions#destroy'
get '/adminsignup' => 'admins#new'
post '/admins' => 'admins#create'
get '/login' => 'sessions#new'
post '/login' => 'sessions#create'
get '/logout' => 'sessions#destroy'
get '/signup' => 'users#new'
post '/users' => 'users#create'
get '/cool' => 'logins#index'
end
Please try
def create
#film = Film.find(params[:film_id])
#review = #film.reviews.new(review_params)
if #review.save
redirect_to film_path(#film)
else
render "films/#{#film.id}"
end
end
I'm trying to create "group posts" that are connected to a "user group" and a user. The first line of my create method is failing with this error:
Couldn't find UserGroup with 'id'=
I've been looking at blog building tutorials thinking that my "group post" is acting like a comment but instead of being attached to an article it's attached to a "user group".
I'm pretty new to Rails so it could be simply a syntax issue. Any advise would be appreciated.
Here is the group post create method:
def create
#user_group = UserGroup.find(params[:user_group_id])
#group_post = current_user.group_posts.new(group_post_params)
if #group_post.save
respond_to do |format|
format.html {redirect_to user_group_path(#user_group), notice: "Group Post created!"}
end
else
redirect_to user_group_path(#user_group), notice: "Something went wrong."
end
end
private
def group_post_params
params.require(:group_post).permit(:content, :post_type, :user_group_id)
end
Here is the user group model:
class UserGroup < ActiveRecord::Base
has_many :group_members, dependent: :destroy
has_many :members, through: :group_members, source: :user
has_many :group_posts, dependent: :destroy
validates :name, presence: true, length: {minimum: 5}
validates :searchable, presence: true, length: {minimum: 5}
def owners
members.includes(:group_members).where('group_members.owner = ?', true)
end
def regular_users
members.includes(:group_members).where('group_members.owner = ?', false)
end
end
Here is the group post model:
class GroupPost < ActiveRecord::Base
include PublicActivity::Model
belongs_to :user
belongs_to :user_group
validates :user_id, :presence => true
validates :content, :presence => true
end
And finally the routes:
Rails.application.routes.draw do
devise_for :users, controllers: {registrations: 'registrations'}
root 'pages#home'
resources :users, only: [:index, :show]
resources :friendships, only: [:create, :destroy, :accept] do
member do
put :accept
end
end
resources :posts, only: [:create, :edit, :update, :destroy]
resources :group_posts, only: [:create, :edit, :update, :destroy]
resources :activities, only: [:index] do
member do
put "upvote" =>"activities#upvote"
end
end
resources :user_groups do
resources :group_posts
resources :group_members
end
end
Here is the form partial submitting the group post:
<div class="posts-panel">
<%= form_for(#group_post) do |f| %>
<%= render 'partials/error_messages', object: f.object %>
<div class="form-group">
<%= f.text_area :content, placeholder: "Compose new post...", class: "form-control" %>
</div>
<div class="form-group">
<%= f.select :post_type, [['Request', 'request'],['Report', 'report']], {}, {class: "form-control"} %>
</div>
<div class="form-group">
<%= hidden_field_tag :user_group_id, #usergroup.id %>
<%= f.submit "Post", class: "btn btn-primary" %>
</div>
<% end %>
</div>
Complete Params:
{"utf8"=>"✓", "authenticity_token"=>"thkRQYNcl+ySSoWIE83V22DEqYdttg+TF4coFsmasXkt2mylgB2YG/vAl2KYRey/djTqL5iNSTIyWJpsSWyCQQ==", "group_post"=>{"content"=>"This is it", "post_type"=>"prayer"}, "user_group_id"=>"1", "commit"=>"Post", "controller"=>"group_posts", "action"=>"create"}
The user_group_id was not inside the params hash. Adding the following line to the create method solved the issue:
#group_post.user_group = #user_group
I have already tried to go through solutions like this, but I'm a Rails beginner and just building my first app after going through Pragmatic Studio Rails I & II Course
Basically, I want to build a simple listing site like BookYogaRetreats.com
I'm trying to figure out how to implement the filter logic. So far I have a listing model, categories & categorizations.
Listing Model:
has_many :categorizations, dependent: :destroy
has_many :categories, through: :categorizations
has_attached_file :image, styles: { :medium => "200x200#" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
validates :title, presence: true, uniqueness: true
paginates_per 15
scope :by_category, lambda { |category| includes(:categories).where(:categories => { :name => category }) }
Categorization Model:
belongs_to :listing
belongs_to :category
Categories Model:
has_many :categorizations, dependent: :destroy
has_many :listings, through: :categorizations
My Listings Controller index action looks like this (I've been experimenting a lot...)
class ListingsController < ApplicationController
before_action :find_listing, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
before_filter :load_data, only: [:index]
def index
#listings = #listings.includes(:categories).where(categories: { id: #category}) if #category_ids
#listings = #listings.page(params[:page])
respond_to do |format|
format.js
format.html
end
end
And in my jumbotron partial, which includes the filter dropdowns I have the following:
<div class="col-sm-6 col-md-4">
<%= select_tag("listing[category_id]", options_from_collection_for_select(#categories, "id", "name") , { :prompt => 'Select a Category' }) %>
<%= submit_tag nil, class: "form_submit", method: "get" %>
</div>
My listings/index.html.erb looks like this:
<% #listings.each_slice(3) do |listings|%>
<div id="listings">
<div class="row">
<% listings.each do |listing|%>
<div class="col-md-4">
<div class="listing">
<div class="image_wrapper">
<%= link_to listing do %>
<%= image_tag listing.image.url(:medium) %>
<% end %>
<h2><%= link_to listing.title, listing %></h2>
<p><%= listing.start_date %> - <%= listing.end_date %></p>
</div>
</div>
</div>
<% end %>
</div>
</div>
I've tried to figure something out for the past two days, been experimenting with Filterific Gem as well as Ransack. I really don't want to use gems and at the moment I don't understand what I need to do. I would be fine with a a category filter, which upon clicking the submit button reloads the page showing all listings that belong to that particular category? Having a has_many through relationship probably doesn't make it easier.
I'd love to be able to have something like listings?by_category=seminars, which then reloads the listings view index.html.erb and only shows the listings that include the category seminars.
I might be completely on the wrong track here. Any pointers would be greatly appreciated.Many thanks.
Managed to find a solution here:
My view:
<%= form_tag listings_path, :controller => 'listings', :action => 'index', :method => 'get', :id => "category_select" do %>
<%= collection_select( nil, :category_id, Category.all, :id, :name, { :include_blank => 'All Categories'} , { :class => 'form-control' }) %>
<%= submit_tag nil, class: "form_submit" %>
<% end %>
My controller index action:
#listings = Listing.includes(:categorizations).page(params[:page])
if params[:category_id].blank?
#listings
else
#category_id = Category.find_by(id: params[:category_id])
#listings = #category_id.listings
end
respond_to do |format|
format.js
format.html
end
This will then allow me to use /listings?category_id=5 and solves the problem. If you have any more elegant tips, please let me know.
I'm using devise for authentication and have users associated with buildings. I can create new users appropriately associated with the right building but devise validation breaks if a new user doesn't have all required inputs.
The code:
app/models/user.rb
class User < ActiveRecord::Base
belongs_to :building
attr_accessible :building_id
...
end
(I known that having building_id attr_accessible is not ideal but I'm not sure how to create the association without using a hidden field for the building_id in the new user registration form...)
class Building < ActiveRecord::Base
has_many :users
...
end
In my routes, user registration is nested within buildings:
devise_for :users, controllers: { :registrations => "registrations" }, skip: [:registrations]
resources :users, except: [:new, :create] do
resource :approvals, only: [:update]
end
match '/:building', to: "buildings#landing"
resources :buildings, except: [:new, :create, :destroy] do
as :user do
get '/signup' => 'registrations#new', as: :new_user_registration
post '/signup' => 'registrations#create', as: :user_registration
end
...
end
app/views/devise/registrations/new.html.erb
<%= simple_form_for(resource, :as => resource_name, :url => building_user_registration_path(), :html => {:class => 'form-inline', :multipart => true }) do |f| %>
<%= render 'fields', f: f %>
<div class="inputs">
<%= f.input :role, collection: User::ROLES.collect %>
<%= f.input :password, :required => true %>
<%= f.input :password_confirmation, :required => true %>
</div>
<div class="actions">
<%= f.button :submit, "Create my account", class: "btn btn-large btn-primary" %>
</div>
<% end %>
And then, finally, the offending line of code in app/views/devise/registrations/_fields.html.erb
...
<%= f.hidden_field :building_id, value: #building.id %>
...
If all of the required fields for the new user are filled in correctly a new user is created that is appropriately associated with the right building. If any of the required fields is blank or invalid, Devise throws the following error in the browser:
RuntimeError in Registrations#create
Showing .../app/views/devise/registrations/_fields.html.erb where line #7 raised:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
Line #7 is: <%= f.hidden_field :building_id, value: #building.id %>
Any thoughts would be greatly appreciated. I'm sure that I'm doing several suboptimal things here...
You can do
<%= f.hidden_field :building_id, value: #building.try(:id) %>
but I would rather not include this field at all if there's no #building set
I got it working with the help of a friend. I already had a custom registration controller (referred to in my routes) and I added a before filter to find the building:
class RegistrationsController < Devise::RegistrationsController
before_filter :find_building, only: [:new, :create]
...
private
def find_building
#building = Building.find_by_slug(params[:building_id])
end
end