On my homepage, I'm trying to set it up so when you click the "Get started" button, a website record is created, but also a page belonging to that website is created, and you're redirected to the page.
This is what I have so far. The website record is being created but the page is not being created.
Models
class Page < ApplicationRecord
belongs_to :website
end
class Website < ApplicationRecord
has_many :pages, :dependent => :destroy
accepts_nested_attributes_for :pages
end
Homepage controller
class MarketingPagesController < ApplicationController
def home
#website = Website.new
#website.pages.build
end
end
Website controller
class WebsitesController < ApplicationController
def create
#website = Website.new(creation_params)
if #website.save
redirect_to #website.Page.first
else
render :new
end
end
private
def shared_params
[:name]
end
def creation_params
params.require(:website).permit(*shared_params)
end
def update_params
params.require(:website).permit(*shared_params)
end
end
Page Controller
class PagesController < ApplicationController
def create
#page = Page.new(creation_params)
if #page.save
redirect_to #page
else
render :new
end
end
def show
#page = Page.find(params[:id])
#templates = Template.all
end
private
def shared_params
[:name, :website_id]
end
def creation_params
params.require(:page).permit(*shared_params)
end
def update_params
params.require(:page).permit(*shared_params)
end
end
Website form on homepage
<%= form_for #website do |f| %>
<%= f.hidden_field :name, value: "Untitled site" %>
<%= f.fields_for :pages do |builder| %>
<%= builder.hidden_field :name, value: "Untitled page" %>
<% end %>
<%= f.submit "Create Website" %>
<% end %>
You are using the association incorrectly
# Change
#website.Page.first
# to
#website.pages.first
Change this snippet in WebsiteController
if #website.save
redirect_to #website.pages.first
else
render :new
end
you have not white listed page params in website controller. modify your shared_params in website controller to :
def shared_params
[:name, pages_attributes: [:id, :name]]
end
and of course do changes suggested by #Deepak
Related
I am building a book review application from on online tutorial. I am trying to save a book review with a form. I have a book table and a reviews table. If the book review saves, I've told the review form to redirect to the book show page. If not, render 'new' again. I get zero errors when I try to save. It just puts me back on the new review page. I went into the console, and the reviews are not being saved. I don't know what's going on. Can someone help?
Here is my books controller:
class BooksController < ApplicationController
before_action :authenticate_user!, only: [:new, :edit, :index, :show]
def index
#books = Book.all
end
def new
#book = current_user.books.new
end
def create
#book = current_user.books.build(book_params)
if #book.save
redirect_to books_path
else
render 'new'
end
end
def show
#book = Book.find(params[:id])
end
def edit
#book = Book.find(params[:id])
end
def update
#book = Book.find(params[:id])
if #book.update(book_params)
redirect_to book_path(#book)
else
render "edit"
end
end
def destroy
#book = Book.find(params[:id])
#book.destroy
if #book.destroy
redirect_to books_path
else
render 'show_books_path'
end
end
private
def book_params
params.require(:book).permit(:title, :description, :author, :category_id, :book_img)
end
end
Here is my reviews controller:
class ReviewsController < ApplicationController
before_action :find_book
def new
#review = Review.new
end
def create
#review = Review.new(review_params)
#review.book_id = #book.id
#review.user_id = current_user.id
if #review.save
redirect_to book_path(#book)
else
render 'new'
end
end
def edit
end
def update
end
def destroy
end
private
def review_params
params.require(:review).permit(:rating, :comment)
end
def find_book
#book = Book.find(params[:book_id])
end
end
Here is my review model:
class Review < ApplicationRecord
belongs_to :books
belongs_to :users
end
Here is my book model:
class Book < ApplicationRecord
belongs_to :user
has_many :reviews
has_attached_file :book_img, styles: { book_index: "250x350>", book_show: "400x600>" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :book_img, content_type: /\Aimage\/.*\z/
end
I'm using a devise form. Here is what I have:
<%= simple_form_for([#book, #book.reviews.build]) do |f| %>
<p>Rating</p>
<%= f.input :rating, label: false, :class => "input" %>
<p>Comment</p>
<%= f.text_area :comment, label: false, :class => "input" %>
<%= f.button :submit, :class => "submit" %>
<% end %>
Here is my routes file:
Rails.application.routes.draw do
devise_for :users
resources :books do
resources :reviews
end
root "books#index"
end
I'm really not sure what's going on here. When I go into the console, the reviews are not being saved. Eventually, I want to display them, but I haven't gotten to that step. Any help would be very appreciated!
I see that in your Review model you have this:
class Review < ApplicationRecord
belongs_to :books
belongs_to :users
end
When it should be like this:
class Review < ApplicationRecord
belongs_to :book
belongs_to :user
end
belongs_to associations have to use the singular term
I am using Devise as my authentication system and simple form. I get a NoMethodError in Groups#show and an undefined method 'name' for nil:NilClass error. I use model associations to tie the groups and posts together. When I do puts post.user.name it correctly displays in my terminal but that line causes the above error and it's referencing Groups#show for some reason. Any thoughts?
Routes
resources :groups do
resources :posts
end
Group Model
class Group < ActiveRecord::Base
validates :user_id, presence: true
belongs_to :user
has_many :posts
has_many :comments
has_many :attachments
end
Post Model
class Post < ActiveRecord::Base
validates :user_id, presence: true
validates :caption, presence: true
belongs_to :user
belongs_to :group
has_many :comments, dependent: :destroy
end
Group Controller
class GroupsController < ApplicationController
before_action :authenticate_user!
def new
#group = current_user.groups.build
end
def create
#group = current_user.groups.build(group_params)
#group.user_id = current_user.id
if #group.save
redirect_to groups_path
else
render :new
end
end
...
private
def group_params
params.require(:group).permit(:group_name, :description, :user_id)
end
end
Posts Controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :owned_post, only: [:edit, :update, :destroy]
before_action :authenticate_user!
def index
#posts = Post.paginate(page: params[:page], per_page: 3).order('created_at DESC')
#post = current_user.posts.build
#attachments = Attachment.all
end
...
def new
#post = current_user.posts.build
end
def create
#post = current_user.posts.build(post_params)
#group = Group.find(params[:group_id])
#post.group_id = #group.id
if #post.save
redirect_to groups_path
else
render :new
end
end
...
private
def post_params
params.require(:post).permit(:caption, :user_id)
end
def set_post
#post = Post.find(params[:id])
end
def owned_post
unless current_user == #post.user
redirect_to root_path
end
end
end
groups/show.html.erb
<%= render "posts/index" %>
...
posts/_index.html.erb
<%= render 'posts/form' %>
<%= render 'posts/posts' %>
...
posts/_form.html.erb
<%= simple_form_for([#group, #group.posts.build]) do |f| %>
...
posts/_posts.html.erb
<% #group.posts.each do |post| %>
<%= puts post.user.name %> ISSUE
<%#<%= render 'posts/post', post: post %>
<% end %>
SOLUTION: After asking on Reddit Rails, a generous user offered a solution that works. Apparently the <%= simple_form_for([#group, #group.posts.build]) do |f| %> creates a new post and adds it to the groups.posts array and so this causes issues when it iterates over _posts.html.erb and there is no user. More information can be found here: https://www.reddit.com/r/rails/comments/4lygix/unidentified_method_for_nil_class_devise_and/
But replace the above simple_form line of code with <%= simple_form_for([#group, Post.new(group: #group)]) do |f| %> seemed to do the trick, as suggested by the generous user in the reddit link above.
I'm building an app that lets :users place :orders at :places. I am defining orders_params in PlacesController, but Rails says ParameterMissing ("params is missing or the value is empty: order")
How can I fix this, so that one can create an :order for :place_id through app/place/PLACE_ID/book ?
PlacesController:
def book
#place = Place.find(params[:id])
#order = Order.new(order_params)
if #order.save
flash[:success] = "Success"
redirect_to #place
else
render 'book'
end
end
private
def place_params
params.require(:place).permit(:place_name)
end
def order_params
params.require(:order).permit(:place_id, :user_id)
end
Routes.rb
get 'book' => 'places#show#book'
get '/places/:id/book' => 'places#book', as: :place_book
resources :places
OrdersController
class OrdersController < ApplicationController
def new
end
def create
#place = Place.find(#order.place_id)
#order = Order.new(user_id: current_user.id, place_id: #place)
if #order.save
flash[:success] = "Order placed"
redirect_to #place
else
render 'book'
end
end
def show
end
def edit
end
def update
end
def destroy
end
private
def order_params
params.require(:order).permit(:place_id, :user_id)
end
end
Model: Order.rb
belongs_to :user
has_one :place
validates :user_id, presence: true
validates :place_id, presence: true
## OTHER VALIDATIONS
View: app/views/places/book
<%= form_for(#order) do |f| %>
<!-- SOME FORM_FORS -->
<%= f.submit "Place order", class: "btn btn-primary" %>
<% end %>
I am trying to render a form to upload a song.
I have a playlist model and a song model, song being a nested resource of playlist.
With simple form, when I try and render the new song partial, I get undefined method songs_path for #<#<Class:0x007fdc51980870>
In routes, the new song path is new_playlist_song but it doesn't seem that simple form knows this.
Songs controller:
class SongsController < ApplicationController
def new
#song = Song.new
end
def create
#song = Song.new(song_params)
if #song.save
flash[:info] = "Song uploaded sensually"
redirect_to user_path(current_user)
else
render 'new'
end
end
def index
#song = Song.all
end
private
def song_params
params.require(:song).permit(:audio)
end
end
Playlists controller:
class PlaylistsController < ApplicationController
before_action :find_playlist, only: [:edit, :update, :destroy]
def index
#playlists = Playlist.all
end
def new
if user_signed_in?
#playlist = current_user.playlists.new
else
redirect_to(root_url)
flash[:danger] = "You have to register to purchase gigs"
end
end
def create
#playlist = current_user.playlists.new
#playlist.user_id = current_user.id
if #playlist.save
redirect_to new_playlist_path
else
render 'new'
end
end
def destroy
#playlist = Playlist.find(params[:id])
if #playlist.present?
#playlist.destroy
redirect_to playlists_path
end
end
private
def find_playlist
#playlist = Playlist.find(params[:id])
end
end
Song model:
class Song < ActiveRecord::Base
belongs_to :playlist
has_attached_file :audio
validates_attachment_presence :audio
validates_attachment_content_type :audio, :content_type => [ 'audio/mp3','audio/mpeg']
end
Playlist model :
class Playlist < ActiveRecord::Base
belongs_to :user
has_many :songs
end
Routes:
resources :playlists do
resources :songs
end
User profile link to create new song:
<p> <%= #user.playlist.user_id %> </p>
<p> <%= #user.playlist.created_at %> </p>
<% if #user == current_user %>
<p> <%= link_to "Uploaad track", new_playlist_song_path(#user) %>
<% end %>
I have tried a few variants for the simple_form form.
New song partial 1:
<%= simple_form_for ([#playlist, #song]) do |f| %>
<%= f.file_field :audio %>
<%= f.button :submit %>
<% end %>
another try :
<%= simple_form_for ([#playlist, current_user.playlist.songs.build]) do |f| %>
I just can't get the form to show and I can't figure out why not. Any ideas would be appreciated, thanks.
As pointed out in the comments songs_path is not referenced in your code, and shouldn't even exist as it's a sub-resource of playlist.
If you want to list all the available routes just run a rake routes and make sure the code references an existing path.
I didn't define the playlist that the song belongs to.
Adding to the controller
def create
#song = current_user.playlist.songs.new song_params
#song.playlist_id = #playlist.id
if #song.save
and
def find_playlist
#playlist = Playlist.find(params[:id])
end
then to simple form
<%= simple_form_for ([#playlist, #playlist.songs.build]) do |f| %>
It works.
I am trying to set up a 5 star rating system so users can rate other users. At the moment everything is working, (create, delete, update etc...) but only the logged in user can rate himself. I cannot rate other users. I get no errors, it just redirects to the user profile page as it should but without added a rating to that user.
user.rb
class User < ActiveRecord::Base
has_many :reviews
review.rb
class Review < ActiveRecord::Base
belongs_to :user
end
reviews_controller.rb
class ReviewsController < ApplicationController
before_action :find_user
before_action :find_review, only: [:edit, :update, :destroy]
def new
#review = Review.new
end
def create
#review = Review.new(review_params)
#review.user_id = current_user.id
if #review.save
redirect_to user_path(#user)
else
render 'new'
end
end
def edit
end
def update
if #review.update(review_params)
redirect_to user_path(#user)
else
render 'edit'
end
end
def destroy
#review.destroy
redirect_to user_path(#user)
end
private
def review_params
params.require(:review).permit(:rating, :comment)
end
def find_user
#user = User.find(params[:user_id])
end
def find_review
#review = Review.find(params[:id])
end
end
_form which then gets rendered on show page:
<%= simple_form_for([#user, #user.reviews.build]) do |f| %>
<div id="rating-form">
<label>Rating</label>
</div>
<%= f.input :comment %>
<%= f.button :submit %>
<% end %>
<script>
$('#rating-form').raty({
path: '/assets/',
scoreName: 'review[rating]'
});
</script>
Any help getting this to work would be greatly appreciated!!
Do this:
#config/routes.rb
resources :users do
resources :reviews, only: [:new, :create]
end
#app/models/review.rb
class Review < ActiveRecord::Base
belongs_to :user
belongs_to :reviewed, class_name: "User", foreign_key: :reviewed_id
end
#app/controllers/reviews_controller.rb
class ReviewsController < ApplicationController
def new
#review = current_user.reviews.new
end
def create
#review = current_user.reviews.new review_params
#review.save
end
private
def review_params
params.require(:review).permit(:rating, :comment).merge(reviewed_id: params[:user_id])
end
end
#app/views/reviews/new.html.erb
<%= form_for #review do |f| %>
<%= f.number_field :rating %>
<%= f.text_field :comment %>
<%= f.submit %>
<% end %>
This would mean you'll have to include a reviewed_id column in your reviews table.
You'll be able to access it using: url.com/users/:user_id/reviews/new
The application will automatically fill the user_id and reviewed_id fields, so the rest of your code should work with the upgrade.
The big problem you have is that you're basically recording the user_id (presumably of who created the review)... but have no way of stipulating who the review is about.
The above code fixes that for you.