has_many build method, Rails
Was my last question. It now works: no errors.
The new problem is that the new unit conversion doesn't associate with an ingredient ID. I thought this was "just supposed to work" from the build method?
Unit Conversion controller:
def new
#ingredient = Ingredient.find(params[:ingredient_id])
#unit_conversion = #ingredient.unit_conversions.build
end
def create
#ingredient = Ingredient.find(params[:ingredient_id])
#unit_conversion = #ingredient.unit_conversions.build(params[:unit_conversion])
if #unit_conversion.save
flash[:notice] = "Successfully created unit conversion."
redirect_to ingredient_unit_conversions_url(#ingredient)
else
render :action => 'new'
end
end
Unit Conversion Model:
class UnitConversion < ActiveRecord::Base
belongs_to :ingredient
end
Ingredient Model:
class Ingredient < ActiveRecord::Base
belongs_to :unit
has_many :unit_conversions
end
Thanks for the help, I'm finding a rough learning curve today :)
EDIT:
One more important thing..
new.html.erb
<h1> New Derived Unit </h1>
<% form_for([#ingredient, #unit_conversion]) do |f| %>
<% f.error_messages %>
<p>
<%= f.label :name %>
<%= f.text_field :name%>
</p>
<p>
<%= f.label :conversionToBase%>
<%= f.text_field :conversionToBase%>
</p>
<p>
<%= f.submit "Create" %>
</p>
<% end %>
<% link_to 'Back', url_for( :controller => 'ingredients', :action => 'show', :id => #ingredient)%>
Make sure that you have form_for [#ingredient, #unit_conversion] in your form.
new.html.erb
<% title "New Unit Conversion" %>
<%= render :partial => 'form' %>
<p><%= link_to "Back to List", ingredient_unit_conversions_path(#ingredient) %></p>
_form.html.erb
<% form_for [#ingredient, #unit_conversion] do |f| %>
<%= f.error_messages %>
<p>
... fields here
</p>
<p><%= f.submit "Submit" %></p>
<% end %>
Related
I'm adding comments for my tweets in my application but I get this error in the view for the first line in my form.
First argument in form cannot contain nil or be empty
Extracted source (around line #1): <%= form_for [#tweet, #comment] do |f| %>
My routes
resources :tweets do
resources :comments
resources :likes
end
My model
class Comment < ApplicationRecord
belongs_to :tweet
belongs_to :user
end
My controller
class CommentsController < ApplicationController
def create
#tweet = Tweet.find(params[:id])
#comment = #tweet.comments.create(params[:comment].permit(:body))
redirect_to tweets_path
end
end
My form
comments/_form.html.erb
<%= form_for [#tweet, #comment] do |f| %>
<p><%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<br>
<br>
<%= f.submit %>
<% end %>
My view (partial)
tweets/_tweets_index.html.erb
<% #tweets.reverse.each do |tweet| %>
....
<%= render tweet.comments %><br>
Add a comment
<%= render partial: 'comments/form' %>
<% end %>
In turn rendered to tweets/index.html.erb
<%= render partial: 'tweets_index' %>
I changed the first line on the form as per previous questions here ..[#foo, #bar].. as above but it still does not work. What am I doing wrong? ty
EDIT: I have made some progress but the following error appears
My form
<%= form_for( :comment , :html => {:class => "form-horizontal", :role => "form"}, url: tweets_path) do |form| %>
<p><%= form.label :body %><br>
<%= form.text_area :body %>
</p>
<br>
<br>
<%= form.submit %>
<% end %>
Error
:param is missing or the value is empty: tweet
def tweet_params
params.require(:tweet).permit(:user_id, :content, { comments: [:body] })
end
{"authenticity_token"=>"79mdlyIOZTUF8hzXhoOpzTHKhk+/5SBrfnUjnImtmek1HyXDA0U/+R6oEOYgmy4H+a2kEppasDDKBobvdpbQdg==", "comment"=>{"body"=>"Test"}, "commit"=>"Save Comment"}
What the error means is that #tweet is nil. So wherever you render this form, make sure that in the respective controller action, you define #tweet.
I'm new to Rails and struggling to get my belongs_to association right. I have an app where a painting belongs to an artist and an artist can have_many paintings. I can create and edit my paintings, however I can not edit or create artists except through the console. Through much Googling I feel I have got myself turned around. Any help would be much appreciated!
Here's my routes.rb file:
MuseumApp::Application.routes.draw do
resources :paintings
resources :paintings do
resources :artists
resources :museums
end
root 'paintings#index'
end
Here's my paintings Controller
def show
#painting = Painting.find params[:id]
end
def new
#painting = Painting.new
##artist = Artist.new
end
def create
safe_painting_params = params.require(:painting).permit(:title, :image)
#painting = Painting.new safe_painting_params
if #painting.save
redirect_to #painting
else
render :new
end
end
def destroy
#painting = Painting.find(params[:id])
#painting.destroy
redirect_to action: :index
end
def edit
#painting = Painting.find(params[:id])
end
def update
#painting = Painting.find(params[:id])
if #painting.update_attributes(params[:painting].permit(:title, :image)) #safe_params
redirect_to #painting
else
render :edit
end
end
Here's the form in my paintings view:
<%= form_for(#painting) do |f| %>
<fieldset>
<legend>painting</legend>
<div>
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div>
<%= f.label :image %>
<%= f.text_field :image %>
</div>
<%= form_for([#painting,#painting.create_artist]) do |f| %>
<div>
<%= f.label :Artist %>
<%= f.text_field :name %>
</div>
</fieldset>
<%= f.submit %>
<% end %>
<% end %>
Artists Controller:
class ArtistsController < ApplicationController
def index
#artists = Artist.all
#artists = params[:q] ? Artist.search_for(params[:q]) : Artist.all
end
def show
#artist = Artist.find params[:id]
end
def new
#artist = Artist.new
end
def create
#painting = Painting.find(params[:painting_id])
#artist = #painting.create_artist(artist_params)
redirect_to painting_path(#painting)
end
def destroy
#artist = Artist.find(params[:id])
#Artist.destroy
redirect_to action: :index
end
def edit
#artist = Artist.find(params[:id])
end
def update
#painting = Painting.find(params[:painting_id])
#artist = #artist.update_attributes(artist_params)
redirect_to painting_path(#painting)
end
end
private
def artist_params
params.require(:artist).permit(:name)
end
Index view:
<h1> Hello and Welcome to Museum App</h1>
<h3><%= link_to "+ Add To Your Collection", new_painting_artist_path %></h3>
<%= form_tag '/', method: :get do %>
<%= search_field_tag :q, params[:q] %>
<%= submit_tag "Search" %>
<% end %>
<br>
<div id="paintings">
<ul>
<% #paintings.each do |painting| %>
<li><%= link_to painting.title, {action: :show, id:painting.id} %> by <%= painting.artist_name %></li>
<div id = "img">
<br><%= link_to (image_tag painting.image), painting.image %><br>
</div>
<%= link_to "Edit", edit_painting_path(id: painting.id) %>
||
<%= link_to 'Destroy', {action: :destroy, id: painting.id},method: :delete, data: {confirm: 'Are you sure?'} %>
<% end %>
</ul>
</div>
In your case you should use accepts_nested_attributes_for and fields_for to achieve this.
Artist
has_many :paintings, :dependent => :destroy
accepts_nested_attributes_for :paintings
Painting
belongs_to :artist
And also you should try creating artist with paintings like this
form_for(#artist) do |f| %>
<fieldset>
<legend>Artist</legend>
<%= f.label :Artist %>
<%= f.text_field :name %>
<%= fields_for :paintings, #artist.paintings do |artist_paintings| %>
<%= artist_paintings.label :title %>
<%= artist_paintings.text_field :title %>
<%= artist_paintings.label :image %>
<%= artsist_paintings.text_field :image %>
</fieldset>
<%= f.submit %>
<% end %>
Note:
You should be having your Artist Controller with at least new,create,edit and update methods defined in it to achieve this.
Edit
Try the reverse
Artist
has_many :paintings, :dependent => :destroy
Painting
belongs_to :artist
accepts_nested_attributes_for :paintings
form_for(#painting) do |f| %>
<fieldset>
<legend>Painting</legend>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :image %>
<%= f.text_field :image %>
<%= fields_for :artists, #painting.artists do |ff| %>
<%= ff.label :Artist %>
<%= ff.text_field :name %>
</fieldset>
<%= f.submit %>
<% end %>
Put this form in paintings views.
I'm new to rails and trying to make a simple site to start learning. When I submit my form, however, the data isn't saved to the db. I'm really not sure what's wrong, I've been trying to figure it out for a while. If I make a record in the rails console and save it, that one successfully shows up in the db (and on the index page).
calculate.rb:
class Calculate < ActiveRecord::Base
attr_accessible :number, :root
end
calculates_controller.rb:
class CalculatesController < ApplicationController
def index
#calculate = Calculate.all
end
def new
#calculate = Calculate.new
end
def create
#calculate = Calculate.new(params[:calculate])
if #calculate.save
redirect_to '/calculates'
else
render 'new'
flash[:notice] = "Didn't work"
end
end
end
new.html.erb:
<%= form_for(#calculate) do %>
<%= label_tag(:number, "Enter the number") %>
<%= text_field_tag :number %>
<%= label_tag(:root, "root") %>
<%= text_field_tag :root %>
<%= submit_tag("Submit") %>
<% end %>
if you are using form_for, use the form_for syntax
<%= form_for(#calculate) do |form| %>
<%= form.label :number %>
<%= form.text_field :number %>
<%= form.label :root %>
<%= form.text_field :root %>
<%= form.submit "Submit" %>
<% end %>
this will automatically handle the routes if the #calculate is new object it will submit it to create or if it is already saved it will send a put request to edit action
Ah hah! I updated my view to:
<%= form_for #calculate, :url => { :action => "create" } do |f| %>
<%= f.label :number %>
<%= f.text_field :number %>
<%= f.label :root %>
<%= f.text_field :root %>
<%= submit_tag("Submit") %>
<% end %>
And now it works. Awesome.
I am working on getting multiple file uploads working for an model in my application, I have included the code below:
delivers_controller.rb
# POST /delivers
def create
#deliver = Deliver.new(params[:deliver])
process_file_uploads(#deliver)
if #deliver.save
flash[:notice] = 'Task was successfully created.'
redirect_to(#deliver)
else
render :action => "new"
end
end
protected
def process_file_uploads(deliver)
i = 0
while params[:attachment]['file_'+i.to_s] != "" && !params[:attachment]['file_'+i.to_s].nil?
deliver.assets.build(:data => params[:attachment]['file_'+i.to_s])
i += 1
end
end
deliver.rb
has_many :assets, :as => :attachable, :dependent => :destroy
validate :validate_attachments
Max_Attachments = 5
Max_Attachment_Size = 5.megabyte
def validate_attachments
errors.add_to_base("Too many attachments - maximum is #{Max_Attachments}") if assets.length > Max_Attachments
assets.each {|a| errors.add_to_base("#{a.name} is over #{Max_Attachment_Size/1.megabyte}MB") if a.file_size > Max_Attachment_Size}
end
assets_controller.rb
class AssetsController < ApplicationController
def show
asset = Asset.find(params[:id])
# do security check here
send_file asset.data.path, :type => asset.data_content_type
end
def destroy
asset = Asset.find(params[:id])
#asset_id = asset.id.to_s
#allowed = Deliver::Max_Attachments - asset.attachable.assets.count
asset.destroy
end
end
asset.rb
class Asset < ActiveRecord::Base
has_attached_file :data,
belongs_to :attachable, :polymorphic => true
def url(*args)
data.url(*args)
end
def name
data_file_name
end
def content_type
data_content_type
end
def file_size
data_file_size
end
end
Whenever I create a new deliver item and try to attach any files I get the following error:
NoMethodError in DeliversController#create
You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
/Users/danny/Dropbox/SVN/railsapps/macandco/surveymanager/trunk/app/controllers/delivers_controller.rb:60:in `process_file_uploads'
/Users/danny/Dropbox/SVN/railsapps/macandco/surveymanager/trunk/app/controllers/delivers_controller.rb:46:in `create'
new.html.erb (Deliver view)
<% content_for :header do -%>
Deliver Repositories
<% end -%>
<% form_for(#deliver, :html => { :multipart => true }) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :caseref %><br />
<%= f.text_field :caseref %>
</p>
<p>
<%= f.label :casesubject %><br />
<%= f.text_area :casesubject %>
</p>
<p>
<%= f.label :description %><br />
<%= f.text_area :description %>
</p>
<p>Pending Attachments: (Max of <%= Deliver::Max_Attachments %> each under <%= Deliver::Max_Attachment_Size/1.megabyte%>MB)
<% if #deliver.assets.count >= Deliver::Max_Attachments %>
<input id="newfile_data" type="file" disabled />
<% else %>
<input id="newfile_data" type="file" />
<% end %>
<div id="attachment_list"><ul id="pending_files"></ul></div>
</p>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>
<%= link_to 'Back', delivers_path %>
Show.html.erb (Delivers view)
<% content_for :header do -%>
Deliver Repositories
<% end -%>
<p>
<b>Title:</b>
<%=h #deliver.caseref %>
</p>
<p>
<b>Body:</b>
<%=h #deliver.casesubject %>
</p>
<p><b>Attached Files:</b><div id="attachment_list"><%= render :partial => "attachment", :collection => #deliver.assets %></div></p>
<%= link_to 'Edit', edit_deliver_path(#deliver) %> | <%= link_to 'Back', deliver_path %>
<%- if logged_in? %>
<%= link_to 'Edit', edit_deliver_path(#deliver) %> |
<%= link_to 'Back', delivers_path %>
<% end %>
_attachment.html.erb (Delivers view)
<% if !attachment.id.nil? %><li id='attachment_<%=attachment.id %>'><a href='<%=attachment.url %>'><%=attachment.name %></a> (<%=attachment.file_size/1.kilobyte %>KB)
<%= link_to_remote "Remove", :url => asset_path(:id => attachment), :method => :delete, :html => { :title => "Remove this attachment", :id => "remove" } %></li>
<% end %>
I have been banging my head against the wall with the error all day, if anyone can shed some light on it, I would be eternally grateful!
Thanks,
Danny
The error message indicates that params[:attachment] is nil inside process_file_uploads(), which causes params[:attachment]['file_'+i.to_s] to raise an exception.
This happens because there's no field named attachment in the form in new.html.erb.
How can I make this work in Rails 2.3?
class Magazine < ActiveRecord::Base
has_many :magazinepages
end
class Magazinepage < ActiveRecord::Base
belongs_to :magazine
end
and then in the controller:
def new
#magazine = Magazine.new
#magazinepages = #magazine.magazinepages.build
end
and then the form:
<% form_for(#magazine) do |f| %>
<%= error_messages_for :magazine %>
<%= error_messages_for :magazinepages %>
<fieldset>
<legend><%= t('new_magazine') %></legend>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>
<fieldset>
<legend><%= t('new_magazine_pages') %>
<% f.fields_for :magazinepages do |p| %>
<p>
<%= p.label :name %>
<%= p.text_field :name %>
</p>
<p>
<%= p.file_field :filepath %>
</p>
<% end %>
</fieldset>
<p>
<%= f.submit :save %>
</p>
</fieldset>
<% end %>
problem is, if I want to submit a collection of magazinepages, activerecord complaints because it's expected a model and not an array.
create action:
def create
#magazine = Magazine.new params[:magazine]
#magazine.save ? redirect_to(#magazine) : render(:action => 'new')
end
In magazine:
accepts_nested_attributes_for :magazinepages
Magazine.new(params[:magazine]) will then handle the object hierarchy for you automatically
I'm not 100% sure what you're asking, but if you're trying to instantiate a new magazine, with many magazinepages, you'll need to iterate over each magazine page. Something like this:
def create
#magazine = Magazine.new(params[:magazine])
if params[:magazinepages]
params[:magazinepages].each do |page|
#magazine.magazinepages.build(page)
end
end
# Save the model, do your redirection or rendering invalid model etc
end