Hi I'm currently working on my first rails project (a photo uploading site), and am getting an error on a form that creates a new photo album that belongs to a user. I'm trying to use the Paperclip gem. It's giving me the error:
ActiveRecord::RecordNotFound in AlbumsController#create
Couldn't find User without an ID
I'm guessing it has something to do with the instance variables in my create action, but I don't see what's wrong. Any guidance would be helpful. Here are my files:
_form.html.erb
<%= form_for (#album), :remote => true, :html => { :id => "uploadform", :multipart => true } do |f| %>
<div>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.fields_for :avatar do |avatar_form| %>
<%= avatar_form.label :avatar, "Upload" %>
<%= avatar_form.file_field :avatar, :multiple => true %>
<% end %>
<%=f.submit %>
</div>
<% end %>
albums_controller create action:
def create
#users = User.all
#user = User.find(params[:user_id])
#album = #user.albums.build(params[:album])
if #album.save
flash[:success] = "Album created!"
end
end
config/routes
Pholder::Application.routes.draw do
resources :users do
resources :albums
end
resources :albums do
resources :pictures
end
Album model
class Album < ActiveRecord::Base
attr_accessible :avatar, :name, :description
has_and_belongs_to_many :users
has_attached_file :avatar
end
Let me know if you need to see any other files.
Since this is a new album, there is no user_id in the albums hash as I first thought. I added a new method that merges in the user id to the hash.
def create
#users = User.all
#album = Album.new(params[:album].merge!(:user_id => current_user))
if #album.save
flash[:success] = "Album created!"
end
end
If you would rather not have user_id in attr_accessible in your Album model, you can assign it separately.
def create
#users = User.all
#album = Album.new(params[:album])
#album.user_id = current_user.id
if #album.save
flash[:success] = "Album created!"
end
end
Related
I've already looked through every other stackoverflow for this issue, but none of the solutions have fixed this. My elements in a nested_form are not being saved in the database. I've also made sure that all model associations are correct. I've been trying to fix this for nearly 8 hours now, and would really appreciate some help, especially considering every other solution hasn't worked.
Basically, I have a Playlist model that contains multiple Song models. I'm trying to use a nested_form to add the Song models to the Playlist. However, none of the Songs are ever being saved. I apologize if my methods are misguides, as I'm still fairly new to Rails.
GitHub Repo:https://github.com/nsalesky/Ultra-Music
playlists_controller.rb
def index
#user = current_user
#playlists = #user.playlists
end
def show
#user = current_user
#playlist = #user.playlists.find(params[:id])
end
def new
#playlist = Playlist.new
#I was told to do this
#playlist.songs.build
end
def create
#user = current_user
#playlist = #user.playlists.create(playlist_params)
if #playlist.save
redirect_to #playlist
else
render :action => 'new'
end
end
def edit
#playlist = current_user.playlists.find(params[:id])
end
def update
#user = current_user
#playlist = #user.playlists.find(params[:id])
if #playlist.update_attributes(playlist_params)
redirect_to #playlist
else
render :action => 'edit'
end
end
def destroy
#user = current_user
#playlist = #user.playlists.find(params[:id])
#playlist.destroy
redirect_to playlists_path(#user.playlists)
end
private
def playlist_params
params.require(:playlist).permit(:name, :description, songs_attributes: [:id, :name, :link, :_destroy])
end
playlist.rb
belongs_to :user
has_many :songs, dependent: :destroy
accepts_nested_attributes_for :songs, :allow_destroy => true, :reject_if => lambda { |a| a[:content].blank? }
validates :name, presence: true
validates_associated :songs, presence: true
_form.html.erb
<%= nested_form_for #playlist do |f| %>
<div>
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div>
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<!--<div>
<button type="button" id="addsong">Add Song</button><br>
<button type="button" id="removesong">Remove Song</button><br>
</div> !-->
<div>
<%= f.fields_for :songs do |song_form| %>
<%= song_form.text_field :name %>
<%= song_form.text_field :link %>
<%= song_form.link_to_remove "Remove Song" %>
<% end %>
<p><%= f.link_to_add "Add Song", :songs %></p>
</div>
<div>
<%= f.submit %>
</div>
<% end %>
In your playlist.rb, you wrote:
:reject_if => lambda { |a| a[:content].blank? }
Here the block parameter |a| stands for attributes of a specific song. So a[:attribute] relates to a single attribute. The problem is your Song doesn't have a :content attribute. So this a[:content].blank? will always be true, means you would be rejected building a song.
Just change a[:content] to a valid attribute such as a[:name]
I am trying to work in my first implementation using fields_for to manage creating has_many relationship in one form partial. This form partial itself is part of a nested resource
So far, I am able to render, save and edit the form successfully without the fields_for nested form.
When I include the fields_for in the form_for, white-list the params, and build the objects in #new, I get this error in the console as it failed to save and re renders the #new view:
(0.1ms) rollback transaction
What can I do to successfully save the form along with the nested_attributes?
routes.rb
....
resources :projects do
resources :step_ones
resources :step_threes
resources :step_twos
resources :step_fours
resources :step_fives
resources :timelines
end
step_four.rb
class StepFour < ApplicationRecord
belongs_to :project
has_many :ios_devices
accepts_nested_attributes_for :ios_devices
end
ios_device.rb
class IosDevice < ApplicationRecord
belongs_to :step_four
end
_form.html.erb
<div>
<%= form_for([#project, #step_four]) do |f| %>
....
<%= f.fields_for :ios_devices do |d| %>
<div class='form-group'>
<%= d.label :full_name, "Name:"%>
<%= d.text_field :full_name %>
<%= d.label :email, "Email:"%>
<%= d.text_field :email %>
<%= d.label :udid, "UDID:"%>
<%= d.text_field :udid %>
<% end %>
<%= hidden_field_tag :project_id, :value => #project.id %>
<div class='row'>
<span class='col-md-6'><%= button_to "Back", project_path(#project), method: :get, class:'btn btn-primary full-wide-button main-btn' %></span>
<span class='col-md-6'><%= f.submit 'Save Data', class: 'btn btn-primary full-wide-button'%></span>
</div>
<% end %>
</div>
step_fours_controller.rb
class StepFoursController < ApplicationController
def new
#project = Project.find(params[:project_id])
#step_four = StepFour.new
3.times { #step_four.ios_devices.build }
end
def create
#step_four = StepFour.new(step_four_params)
#project = Project.find(params[:project_id])
#step_four.ios_devices.each do |d|
puts d.full_name
puts d.email
puts d.udid
end
#step_four.project_id = params[:project_id]
if #step_four.save
flash[:success] = "Step Five Data Saved"
redirect_to #project
else
flash[:danger] = "Data Not Saved. Please Try Again"
render "new"
end
end
def show
#step_four = StepFour.where(project_id: (params[:project_id])).first
end
def update
#step_four = StepFour.where(project_id: (params[:project_id])).first
#project = Project.find(params[:project_id])
if #step_four.update_attributes(step_four_params)
flash[:success] = "Step Four Data Saved"
redirect_to #project
else
flash[:danger] = "Data Not Saved. Please Try Again"
render 'edit'
end
end
def edit
#step_four = StepFour.where(project_id: (params[:project_id])).first
#project = Project.find(params[:project_id])
end
def step_four_params
params.require(:step_four).permit(:iphone_name, :iphone_nickname, :android_name, ios_devices_attributes: [:id, :full_name, :email, :udid])
end
end
After realizing that the error was upon the save method, I tried to force the issue and raise an exception with a shebang ! . I received a Validation error that lead me to this question:
Error: Validation failed: Images imageable must exist , rails-5.0 , paperclip-5
I needed to add optional: true to the belongs_to: step_four in the ios_device model since, I believe that the object doesn't exist yet.
Now everything is working
For my application, I have Projects. I have used Polymorphism to build a model called "Newcomment" for comments made on these Projects. I followed this railscast. This works great.
But now, I want to build comments on top of comments. I tried following this tutorial (http://kconrails.com/2010/10/23/nested-comments-in-ruby-on-rails-1-models/) and (http://kconrails.com/2011/01/26/nested-comments-in-ruby-on-rails-controllers-and-views/). I put a form for comments in each comment that I render. I also adjusted the newcomment.rb model, so that newcomment has_many newcomments and the routes.rb file.
Question: Right now, when I make a comment in the form of each comment, it posts as a comment to the project and not as a response to a specific comment. How would I adjust my code so that I can have comments for comments?
newcomment.rb
class Newcomment < ActiveRecord::Base
attr_accessible :content, :user_id
belongs_to :commentable, polymorphic: true
has_many :newcomments, :as => :commentable
belongs_to :user
scope :newest, order("created_at desc")
validates :content, presence: true
end
newcomments_controller.rb
class NewcommentsController < ApplicationController
before_filter :load_commentable
before_filter :authenticate_user!
def create
#newcomment = #commentable.newcomments.new(params[:newcomment])
if #newcomment.save
redirect_to comments_project_path(#commentable), notice: "Comment created."
else
render :new
end
end
def destroy
if current_user.try(:admin?)
#newcomment = Newcomment.find(params[:id])
#commentable = #newcomment.commentable
#newcomment.destroy
if #newcomment.destroy
redirect_to comments_url, notice: "Comment deleted."
end
else
#newcomment = Newcomment.find(params[:id])
#commentable = #newcomment.commentable
#newcomment.destroy
if #newcomment.destroy
redirect_to comments_project_path(#commentable), notice: "Comment deleted."
end
end
end
private
def load_commentable
resource, id = request.path.split('/')[1,2]
#commentable = resource.singularize.classify.constantize.find(id)
end
end
routes.rb
resources :projects do
resources :newcomments do
resources :newcomments
end
end
view/projects/_comments.html.erb
<%= render #newcomments %>
projects_controller.rb
def comments
#commentable = #project
#newcomments = #commentable.newcomments.newest.page(params[:comments_page]).per_page(10)
#newcomment = Newcomment.new
end
view/newcomments/_newcomment.html.erb
<div class="comments">
<%= link_to newcomment.user.name %></strong>
Posted <%= time_ago_in_words(newcomment.created_at) %> ago
<%= newcomment.content %>
</div>
<span class="comment">
<%= form_for [#commentable, #newcomment] do |f| %>
<div class="field">
<%= f.text_area :content, rows: 3, :class => "span8" %>
</div>
<%= f.hidden_field :user_id, :value => current_user.id %>
<div class="actions">
<%= f.submit "Add Comment", :class => "btn btn-header" %>
</div>
<% end %>
<% unless newcomment.newcomments.empty? %>
<%= render #newcomments %>
<% end %>
</span>
All you need, instead of working on it from a scrap, is: https://github.com/elight/acts_as_commentable_with_threading
You should not have the routes like this
resources :newcomments do
resources :newcomments
end
which is a bad smell and we need to fix. In some of our projects, we are also using https://github.com/elight/acts_as_commentable_with_threading and it's good.
for now i've got followings:
model => User (name, email)
has_and_belongs_to_many :trips
model => Trip (dest1, dest2)
has_and_belongs_to_many :users
validates :dest1, :dest2, :presence => true
model => TripsUsers (user_id, trip_id) (id => false)
belongs_to :user
belongs_to :trip
As you see from the code, trip model has validation on dest1, and dest2, but it's not showing up an errors. Controller and view defined as follow:
trips_controller.rb
def new
#user = User.find(params[:user_id])
#trip = #user.trips.build
end
def create
#user = User.find(params[:user_id])
#trip = Trip.new(params[:trip])
if #trip.save
#trip.users << #user
redirect_to user_trips_path, notice: "Success"
else
render :new
end
end
_form.html.erb
<%= simple_form_for [#user, #trip] do |f| %>
<%= f.error_notification %>
<%= f.input :dest1 %>
<%= f.input :dest2 %>
<%= f.submit "Submit" %>
<% end %>
According to the rails guide on presence validation, it can't be used with associated objects. Try to use a custom validation:
validate :destinations_presence
def destinations_presence
if dest1.nil?
errors.add(:dest1, "missing dest1")
elsif dest2.nil?
errors.add(:dest1, "missing dest2")
end
end
I have a Recipe model, which has Ingredients embedded in it, using Mongoid.
class Recipe
include Mongoid::Document
include Mongoid::Timestamps
field :title, :type => String
embeds_many :ingredients
accepts_nested_attributes_for :ingredients, :reject_if => lambda { |a| a[:title].blank? }, :allow_destroy => true
validates :title, :presence => true
end
class Ingredient
include Mongoid::Document
field :name, :type => String
field :quantity, :type => String
embedded_in :recipe, :inverse_of => :ingredients
end
I want to be able to create a new recipe, and the associated ingredients for that recipe, at the same time, but I'm struggling to understand how I'd go about doing this. This is what I have thus far:
_form.html.erb - Used in Recipe views
<%= form_for #recipe do |f| %>
...
<li>Title: <%= f.text_field :title %></li>
<% f.fields_for :ingredients do |builder| %>
<%= render "ingredient_fields", :f => builder %>
<% end %>
...
<%= f.submit %>
_ingredient_fields.html.erb
<%= f.text_field :name %>
Recipe Controller
def new
#recipe = Recipe.new
#ingredient = #recipe.ingredients.build
end
def create
#recipe = Recipe.new(params[:recipe])
if #recipe.save
redirect_to #recipe, notice: 'Recipe was successfully created.'
else
render action: "new"
end
end
Ingredients Controller
def new
#recipe = Recipe.find(params[:recipe_id])
#ingredient = #recipe.ingredients.build
end
def create
#recipe = Recipe.find(params[:recipe_id])
#ingredient = #recipe.ingredients.build(params[:ingredient])
# if #recipe.save
end
This renders the new ingredients form, but there are no fields for the ingredients. Can anyone give me any pointers as to what I'm doing wrong?
When you show the nested form, try using (notice the equals):
<%= f.fields_for
Instead of just
<% f.fields_for
See this similar question.
I had a very similar issue recently. I found this similar question posted on the Mongoid issue tracker on Github to be very helpful:
https://github.com/mongoid/mongoid/issues/1468#issuecomment-6898898
The skinny is that the line
= f.fields_for :ingredients do |builder|
should look like this:
= f.fields_for #recipe.ingredients do |builder|