I have a User model that has_many Photos (another model). In the routes.rb file it's photos is a nested resource of user. So, I have a form_for that uploads to the controller #create action. I'm having trouble saving the photo into the database under the user. How can I do this? It says it saves correctly, because it redirects, but then it doesn't show that it has a photo (I also used the console to check not just my view). What am I doing wrong?
class PhotosController < ApplicationController
def new
#photo = Photo.new(:user_id => params[:user_id])
end
def create
byebug
#photo = Photo.new(params[:user_id])
if #photo.save
flash[:notice] = "Successfully added photo."
redirect_to new_user_photo_path
else
render :action => 'new'
end
end
end
EDIT----------
Adding in the form_for that gets us to the #create action. Hope this helps :) I've been reading more about this, and I'm still not sure what to do to fix.
<%= form_for #photo, :url => user_photos_path(current_user.id, #photo), :html => {:multipart => true} do |f| %>
<div class="form-group">
<%= f.file_field :image %>
</div>
<%= f.submit 'Upload', class: 'btn btn-success' %>
or
<%= link_to 'Cancel', users_path %>
<% end %>
class PhotosController < ApplicationController
def new
#user = User.find(params[:user_id])
#photo = Photo.new(:user_id => params[:user_id])
#photos = #user.photos
end
def create
#photo = User.find(params[:user_id]).photos.new(photo_params)
if #photo.save
flash[:notice] = "Successfully added photo."
redirect_to new_user_photo_path
else
render :action => 'new'
end
end
# GET /photos
def index
redirect_to new_user_photo_path
end
# GET /photos/1
def show
#photo = Photo.find(params[:id])
end
def edit
#photos = Photo.all
#photo = Photo.new
end
def destroy
#photo = User.find(params[:user_id]).photos.find(params[:id])
#photo.destroy
flash[:notice] = "Successfully deleted photo"
redirect_to new_user_photo_path
end
def photo_params
params.require(:photo).permit!
end
end
Related
EDIT: I managed to delete! i had to define teh instance variable #movies = Movie.find(params[:id]) to the delete method in the controller.
I still can't update though. I get "param is missing or the value is empty: movie"
I forgot to add my contrller! sorry!
I'm trying to replicate one of my in class exercises into another app, for practice.
The idea is to be able to add new movies into a database, and get the option to update their info, and delete them as well. I can add new content, but I can't update them or delete them.
Appreciate any inputs I can get.
Routes.rb
Rails.application.routes.draw do
root "movies#index"
get "/movies", to: "movies#index"
get "/movies/new", to: "movies#new", as: "new_movie"
get '/movies/:id', to: "movies#movie_page", as: "movie_page"
post "/movies", to: "movies#add"
get "/movies/:id/edit", to: "movies#edit", as: "movie_edit"
put "/movies/:id", to: "movies#update"
patch "/movies/:id", to: "movies#update", as: "update_movie"
delete "/movies/:id", to: "movies#delete", as: "delete_movie"
end
Controller
class MoviesController < ApplicationController
def index
#movies = Movie.all
end
def movie_page
#movies = Movie.find(params[:id])
end
def new
#movies = Movie.new
end
def add
#movies = Movie.create(movie_params)
redirect_to movies_path
end
def edit
#movies = Movie.find(params[:id])
end
def update
#movies.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
def delete
#movies = Movie.find(params[:id])
#movies.destroy
# flash[:notice] = "Shirt was deleted."
redirect_to root_path, notice: "Shirt was deleted."
end
def movie_params
params.require(:movie).permit(:title, :description, :year_released)
end
# def set_movie
# #movies = Movie.find(params[:id])
# end
end
Form partial
<%= form_for #movies do |m| %>
<p>
<%= m.label :title %><br>
<%= m.text_field :title %>
</p>
<p>
<%= m.label :description %><br>
<%= m.text_field :description %>
</p>
<p>
<%= m.label :year_released %><br>
<%= m.text_field :year_released %>
</p>
<p>
<%= m.submit %>
</p>
<% end %>
Movie page html (individual movies, labeled by IDs)**I can't update or Delete, no route matches Delete.
When I press Update - I get param is missing or the value is empty: movie
<h1><%= #movies.title %></h1>
<h2>Released on : <%= #movies.year_released %> </h2>
<p> <%= #movies.description %> </p>
<%= link_to "Update", movie_edit_path(#movies) %>
<%= link_to "Delete", movies_path, method: :delete %
Edit page *I cant access this link. the form is the problem
<h1>Edit <%= #movies.title %> Info </h1>
<%= render "form" %>
<%= link_to "Cancel Edit", movie_edit_path(#movies) %>
Many thanks guys
def update
#movie = Move.find(params[:id])
#movie.update(movie_params)
redirect_to movie_path(#movie)
end
on your routes. all you need is resources :movies
you are getting param is empty because you have to pass in the id of the movie to update.
The major issue is that you do not load the variable #movies from the DB before you use it.
def update
#movies.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
def update
#movies.find(params[:id])
#movie.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
Aside from that you have tons of duplication and quite a few idiosyncrasies.
Rails uses these naming conventions for actions:
index
show (not movie_page)
new
create (not add)
edit
update
destroy (not delete)
You should follow them unless you have a damn good reason not to.
class MoviesController < ApplicationController
# cuts the duplication
before_filter :set_movie, except: [:new, :index]
def index
#movies = Movie.all
end
# GET /movies/:id
def show
end
# GET /movies/new
def new
#movie = Movie.new
end
# POST /movies
def create
#movie = Movie.create(movie_params)
redirect_to movies_path
end
# GET /movies/edit
def edit
end
# PUT|PATCH /movies/:id
def update
#movie.update(movie_params)
redirect_to #movie, notice: "Shirt was updated."
end
# DELETE /movies/:id
def destroy
#movie.destroy
redirect_to action: :index
end
private
def movie_params
params.require(:movie).permit(:title, :description, :year_released)
end
def set_movie
# Use the singular form when naming a variable with a single record
# failure to do so may result in tarring and feathering
#movie = Movie.find(params[:id])
end
end
I have an Items model that has_many Photos (which belongs_to Items), both namespaced under Admin.
Uploading via the form works as expected via the Photo's new or edit action(, but not when rendered from the Item show page, I get an "undefined method `model_name' for NilClass:Class" error.When I create a new photo record I pass in the item_id and I'm not sure what to pass into the form on the items page.
PhotosController;
class Admin::PhotosController < Admin::BaseController
def new
#photo = Photo.new(:item_id => params[:item_id])
end
def create
#photo = Photo.new(params[:photo])
if #photo.save
flash[:notice] = "Successfully created photo."
redirect_to [:admin,#photo.item]
else
render :action => 'new'
end
end
def edit
#photo = Photo.find(params[:id])
end
def update
#photo = Photo.find(params[:id])
if #photo.update_attributes(params[:photo])
flash[:notice] = "Successfully updated photo."
redirect_to [:admin,#photo.item]
else
render :action => 'edit'
end
end
def destroy
#photo = Photo.find(params[:id])
#photo.destroy
flash[:notice] = "Successfully destroyed photo."
redirect_to [:admin,#photo.item]
end
end
photos/_form.html.haml;
= form_for [:admin,#photo], :html => {:multipart => true,id: 'upload'} do |f|
= f.hidden_field :item_id
%p
= f.label :name
%br/
= f.text_field :name
%p
= file_field_tag :image, multiple: true, name:'photo[image]',id: 'photo_image'
%p= f.submit
items/show.html.haml;
= render 'admin/photos/form'
doh! figured it out
the render call should be;
= render 'admin/photos/form', :photo => #item.photos.build
and the form
= form_for [:admin,photo]
or you can create a #photo variable in your items_controller#show like
#photo = #item.photos.build
and in your partial
form_for[:admin,#photo]
i think this would be better, because all of your variables get assigned in the controller and not one in the controller and the other in the view.
<%= link_to_function "Back", "history.back()" %>
The above does not work in new and edit.html.erb. The back link points to itself (/new# or /edit#) so it does not really go anywhere back. However the back button works in index.html.erb.
See another stackoverflow post on back button:
'Back' browser action in Ruby on Rails
Any thoughts? Thanks.
PS: Category controller:
class CategoriesController < ApplicationController
before_filter :require_signin
before_filter :require_employee
def index
if session[:eng_dh]
#categories = Category.all
else
#categories = Category.active_cate.all
end
end
def new
#category = Category.new
end
def create
if session[:eng_dh]
#dynamic attr_accessible
#category = Category.new(params[:category], :as => :roles_new)
if #category.save
##categories = Category.all
redirect_to categories_path, :notice => 'Category was successfully created.'
# send out email
#NotifyMailer.new_prod_email(#product).deliver
else
render :action => "new"
end
end
end
def edit
#category = Category.find(params[:id])
end
def update
#category = Category.find(params[:id])
##category.reload. caused nil.reload error
if #category.update_attributes(params[:category], :as => :roles_update)
##category = Category.find(params[:id])
redirect_to categories_path, :notice => 'Category was successfully updated'
else
#categories = Category.all
render 'index'
end
end
def show
#category = Category.find[params[:id]]
end
end
A 'Back' link that satisfies most Rails applications' needs is to use the link_to helper:
<%= link_to "Back", :back %>
The :back Symbol option is even noted in the Rails API docs.
I'm having a problem getting my first app (I'm a total newbie) to save a new associated record. I have two models (users and pictures) with a has_many/belongs_to association. I have set up the userController so that it can create a new picture as below:
def new_picture
#user = User.find(current_user.id)
#picture = #user.pictures.build
end
def create_picture
#user = User.find(params[:id])
#picture = #user.pictures.build(params[:picture])
if #picture.save
flash[:notice] = "Your picture was successfully added."
redirect_to :action => 'show', :id => #user.id
else
render :template => "new_picture"
end
end
and I use
<%= link_to("add picture", :action => 'new_picture', :id => #user.id) if current_user %>
to add a new one. But I'd also like to be able to edit. So I updated the usercontroller with some new code:
def edit_picture
#user = User.find(current_user.id)
#picture = #user.pictures.find(params[:id])
end
# When the user clicks the save button update record
def update_picture
#user = User.find(current_user.id)
#picture = #user.pictures.find(params[:picture])
respond_to do |format|
if #picture.update_attributes(params[:picture])
flash[:notice] = "Your picture was successfully updated."
redirect_to :action => 'show', :id => #user.id
else
render :template => "new_picture"
end
end
end
and added the edit link to show.erb:
<%= link_to("edit picture", :action => 'edit_picture', :id => picture.id) if current_user %>
It loads the edit form fine, with the data all in the right place, but on save all it's doing is giving me the error 'ArgumentError in UsersController#update_picture' with a bunch of Unknown key(s) from my pictures table.
Could somebody explain why? I feel like there is one piece of the jigsaw I haven't quite understood here....
Thanks in advance!
UPDATE: View code is as follows:
<h1>New picture for <%= #user.name %></h1>
<% form_for :picture, #picture, :html => { :multipart => true }, :url => {:action => 'update_picture', :id => #user.id} do |f| %>
Can't seem to see your problem in the view code, however you can do the same thing more elegantly (RESTful) as a nested route. That way you might be able to see the problem more clearly.
config/routes.rb:
resources :users do
member do
resources :pictures
end
end
app/controllers/pictures_controller.rb:
class PicturesController < ApplicationController
before_filter :find_picture, :only => [:edit, :update]
def edit
end
def update
if #picture.update_attributes params[:picture]
flash[:notice] = "Your picture was successfully updated."
redirect_to user_path(current_user)
else
render :edit
end
end
protected
def find_picture
#picture = current_user.pictures.find params[:id]
end
end
app/views/pictures/edit.html.erb:
<%= form_for [current_user, #picture] do |f| %>
<!-- some stuff -->
<% end %>
and to link to your edit form:
<%= link_to_if current_user, 'edit picture',
edit_user_picture_path(:user => current_user, :id => picture) %>
I suggest adding 'accepts_nested_attributes_for :pictures to the user model, and then do
<%= form_for #user do |form| %>
.. user fields
<%= form.fields_for :pictures do |picture_form| %>
.. picture fields
<% end %>
<%= form.submit %>
<% end %>
in the view.
Another option is to create a new controller for the pictures. That may be simpler.
I have 2 tables: venues and reviews where 1 venue can have many reviews and a review belongs to a venue. I currently add the reviews to the venues from a link in the venue show page to the reviews new page:
venues/show.html.erb
<div class="button">
<%= link_to 'Add a review', new_venue_review_path(#venue) %>
</div>
reviews/new.html.erb
<% form_for [#venue, #review] do |f| %>
<p>title: <br>
<%= f.text_field :title %></p>
<%= submit_tag %>
<% end %>
reviews controller
def new
#review = Review.new
end
def create
#review = Review.new params[:review]
#review.venue = #venue
if #review.save
flash[:notice] = 'Review added'
redirect_to venue_path(#venue)
else
render :action => :new
end
end
venues controller
class VenuesController < ApplicationController
def index
if
#venues = Venue.with_type(params[:venuetypes]).with_area(params[:areas])
else
#venues = Venue.all
end
end
def new
#venue = Venue.new
end
def create
#venue = Venue.new params[:venue]
if #venue.save
flash[:notice] = 'Venue added'
redirect_to venues_path
else
render :action => :new
end
end
def edit
#venue = Venue.find(params[:id])
end
def update
#venue = Venue.find(params[:id])
#venue.attributes = params[:venue]
if #venue.save!
flash[:notice] = 'Venue updated successfully'
redirect_to venues_path(#venue)
end
end
def show
#venue = Venue.find(params[:id])
end
end
routes
resources :venues do
resources :reviews
end
end
How can I move the add new review form directly into the venues show page? Moving the code over gives a undefined method `model_name' for NilClass:Class error.
Thanks for any help!
Just add #review = Review.new to the show action on your venues controller. Then put the form right in your venue#show view file.
venues_controller.rb
def show
#venue = Venue.find(params[:id])
#review = Review.new
end