partial form for nested models in rails 3 - ruby-on-rails

I have two models pages and author, here is the code of model pages:
edit -1
now my models are as follows:
class Page < ActiveRecord::Base
validates :title, :presence => true
belongs_to :author
end
author model:
class Author < ActiveRecord::Base
has_many :pages
end
and my form is as follows:
<%= form_for(#page) do |f| %>
<% if #page.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#page.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #page.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.fields_for :author do |fields| %>
<%= f.label :author %><br />
<%= fields.text_field :author %>
<% end %>
</p>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :reference %><br />
<%= f.select(:reference,[['google',1],['yahoo',2],['MSN',3],['Ask',4]]) %>
</p>
<%= f.submit "Submit" %>
<% end %>
and controller :
class PagesController < ApplicationController
def index
#total = Page.count
#pages = Page.find(:all)
end
def show
#page = Page.find(params[:id])
end
def new
#page = Page.new
end
def create
#page = Page.new(params[:page])
if #page.save
redirect_to pages_path, :notice => "The data has been saved!"
else
render "new"
end
end
def edit
#page = Page.find(params[:id])
end
def update
#page = Page.find(params[:id])
if #page.update_attributes(params[:page])
redirect_to pages_path, :notice => "Your post has been updated!"
else
render "edit"
end
end
def destroy
#page = Page.find(params[:id])
#page.destroy
redirect_to pages_path, :notice => "Your page has been deleted!"
end
end
Now when i am submitting the form it is giving me this error:
ActiveRecord::AssociationTypeMismatch in PagesController#create
Author(#40328004) expected, got ActiveSupport::HashWithIndifferentAccess(#32291496)
Rails.root: C:/rorapp
Application Trace | Framework Trace | Full Trace
app/controllers/pages_controller.rb:19:in `new'
app/controllers/pages_controller.rb:19:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"hzBlXsdUjEDDCLp036R8bJBwep6BdATSvJPNwt0M8Dg=",
"page"=>{"title"=>"",
"body"=>"",
"author"=>{"author"=>""},
"email"=>"",
"reference"=>"1"},
"commit"=>"Submit"}
Show session dump
Show env dump
Response
Headers:
None
and one more problem if I add accepts_nested_attributes_for :author to my Page model, then the field is not displayed at all. I really want to accomplish this.. any help?

Apparently this doesn't work in reverse with the association. I'm sorry for the mistake. You could do the following, but then your pages controller is acting on the author, which isn't really appropriate. You could make an author controller though, and include fields_for :pages, to have the author and the first page created at the same time.
class PagesController < ApplicationController
def new
#author = Author.new
#page = #author.pages.new
end
def create
#author = Author.create(params[:author])
end
end
class Author < ActiveRecord::Base
has_many :pages
accepts_nested_attributes_for :pages
end
class Page < ActiveRecord::Base
belongs_to :author
end
<%= form_for(#author, :url => pages_url) do |f| %>
<%= f.text_field :author %>
<%= f.fields_for :pages do |fields| %>
<%= fields.text_area :body %>
<% end %>
<% end %>

Related

Rails4: How to pass dynamic array from view to controller

I have a problem creating Vote which contains value of points that user decided to give for a candidate (Borda Count Method). Values are in number_fields and I want them to be saved in Vote objects.
In my case I am only able to get value from the last number_field and I have no idea how to fix it. Other values are being overwritten so I came up with idea to create an array of points which contains values taken from many number_field_tag and pass them from view to controller.
Something about survey structure:
There is a Surv (survey) which contains many Polls (questions).
One Poll contains many Vote Options.
There are also Votes which save votes of user.
OUTPUT from params
{"utf8"=>"✓", "poll"=>{"id"=>"11"}, "9"=>"17", "arr"=>"1212", "pnts"=>"", "10"=>"20", "11"=>"22", "commit"=>"Zagłosuj", "controller"=>"votes", "action"=>"create"}
VIEW:
show.html.erb
<p id="notice"><%= notice %></p>
<h2>Twoja ankieta:</h2>
<h1>
<%= #surv.topic %>
</h1>
<h2>
<%= election_type %>
</h2>
<%= render 'voting_form' %>
<%= link_to 'Edit', edit_surv_path(#surv) %> |
_voting_form.html.erb
<%= form_tag votes_path, method: :post, remote: true, id: 'voting_form' do %>
<% if #surv.votingtype == "default" %>
<%# here is unnecessary code ... %>
<% elsif #surv.votingtype == "bordy" %> <%# BORDY %>
<% #polls.each do |poll| %>
<h2><%= poll.topic %></h2>
<h2>POLL ID: <%= poll.id %></h2>
<%= hidden_field_tag 'poll[id]', poll.id %>
<%= arr = [] %>
<%= i = 0 %>
<% poll.vote_options.each do |option| %>
<div class="form-group">
<%= content_tag(:label) do %>
<div class="select">
<%= option.title %>
<%= radio_button_tag option.poll_id, option.id %>
<%# if selected then vote is created %>
<%= number_field_tag :point %>
<%#= arr << :point %>
<%= hidden_field_tag 'pnts', arr %>
<%# some tries to pass params %>
</div>
<% end %>
<%= visualize_votes_for option %>
</div>
<% end %>
<p><b>Głosów razem: <%= poll.votes_summary %></b></p>
<% end %>
<% if current_user && current_user.voted_for3?(#surv) %>
<p>Twój głos został DO ANKIETY został zapisany.</p>
<% else %>
<%= submit_tag 'Zagłosuj', class: 'btn btn-lg btn-primary' %>
<% end %>
<% end %>
<% end %>
CONTROLLER:
votes_controller.rb
class VotesController < ApplicationController
def create
#poll = Poll.find_by_id(params[:poll][:id])
#surv = Surv.find_by_id(#poll.surv_id)
puts "Surv id:"
puts #surv.id
#surv.polls.each do |p|
puts "Poll ID (poll voted)."
puts p.id
puts "Vote option ID (vote option voted)"
puts params[p.id.to_s]
#option = p.vote_options.find_by_id(params[p.id.to_s])
if p && !current_user.voted_for?(p)
#here i would like to grab params specially specified for each poll
#vote = #option.votes.create({user_id: current_user.id, points: params[:pnts]})
##vote = #option.votes.create({user_id: current_user.id, points: params[:point]})
puts 'POINTS'
puts params.inspect
else
render js: 'alert(\'Glosowales juz w tej ankiecie!\');'
return
end
# end
end
#surv.update_attribute(:actual_votes, #surv.actual_votes+1)
if (#surv.maximum_votes > 0 && #surv.actual_votes >= #surv.maximum_votes)
respond_to do |format|
format.html { redirect_to terminate_surv_path(#surv), notice: 'Ostatni głos został oddany' }
format.js {render inline: "location.reload();" }
end
end
end
def vote_params
params.require(:vote).permit(:points)
end
end
MODEL:
vote_option.rb
class VoteOption < ActiveRecord::Base
belongs_to :surv
accepts_nested_attributes_for :surv
belongs_to :poll
accepts_nested_attributes_for :poll
has_many :votes, dependent: :destroy
has_many :users, through: :votes
validates :title, presence: true
end
vote.rb
class Vote < ActiveRecord::Base
belongs_to :user
belongs_to :vote_option
end
def surv_params
params.require(:surv).permit(:topic, :votingtype,
polls_attributes: [:id, :topic, :endtime, :endontime, :_destroy,
vote_options_attributes: [:id, :title, :_destroy]
])
end
Please let me know if you need some additional code or informations to help me fix my problem. Thank you in advance

Could not save values in Nested forms using rails 5

I am stuck up with building nested forms using Ruby on Rails.
I am trying to build a form which has fields from three tables(User, Contact, Address). User table has address_id and contact_id. When user fills the details, contact details should be saved in contact table and address should be saved in address table. Both the ids should get saved in user table along with the user details. How should I proceed?
My model,
class Address < ApplicationRecord
has_one :user
end
class Contact < ApplicationRecord
has_one :user
end
class User < ApplicationRecord
belongs_to :address
belongs_to :contact
end
My controller,
class UsersController < ApplicationController
def new
#user = User.new
#user.build_contact
#user.build_address
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:name, :email, contact_attributes: [:phone], address_attributes: [:street, :city])
end
end
And my view is,
<%= form_for(user) do |f| %>
<% if user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %>
<%= f.text_field :email %>
</div>
<%= f.fields_for :contact do |c| %>
<div class="field">
<%= c.label :phone %>
<%= c.text_field :phone %>
</div>
<% end %>
<%= f.fields_for :address do |a| %>
<div class="field">
<%= a.label :street %>
<%= a.text_field :street %>
</div>
<div class="field">
<%= a.label :city %>
<%= a.text_field :city %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Is my approach right? Kindly please suggest. Thanks in advance.
You missing a couple of lines...
class User < ApplicationRecord
belongs_to :address
belongs_to :contact
accepts_nested_attributes_for :address
accepts_nested_attributes_for :contact
end
Also ensure you accept :id and :_delete
params.require(:user).permit(:name, :email, contact_attributes: [:id, :phone, :_delete], address_attributes: [:id, :street, :city, :_delete]

Rails passing params to different model and then saving it not working

I have a 'post' controller in that I have two variable title and body which I am passing through strong parameters.But I need to use two other variable which are path and name which are in different model name 'Document'..And also I am saving the content in database ..but unable to do so..getting this error view [posts/_form.html.erb]
undefined method `name' for #
[posts_controller]
class PostsController < ApplicationController
before_action :authenticate_user!
def index
#posts = Post.user_post(current_user).order('created_at DESC').paginate(:page => params[:page], :per_page => 5)
end
def new
#post = Post.new
end
def show
#post = find_params
end
def create
#post = Post.create(post_params)
#post.user = current_user
if #post.save
redirect_to #post
else
render 'new'
end
end
def edit
#post = find_params
end
def update
#post = find_params
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
def destroy
#post = find_params
#post.destroy
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:title, :body)
Document.new(params,:files=>[])
end
def find_params
Post.find(params[:id])
end
end
[post/_form.html.erb]
<%= form_for #post,html: { multipart: true } do |f| %>
<% if #post.errors.any? %>
<div id="errors">
<h2><%= pluralize(#post.errors.count, "error") %> prevented this post from saving:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label :title %><br>
<%= f.text_field :title %><br>
<br>
<%= f.label :body %><br>
<%= f.text_field :body %><br>
<br>
<%= f.label :name %> <br>
<%= f.text_field :name %><br>
<br>
<br>
<%= f.label :path %><br>
<%= f.file_field :path %><br>
<%= f.submit %>
<% end %>
[document.rb]
class Document < ActiveRecord::Base
validates :name, presence: true
validates :path, presence: true
validates :resource_type, presence: true
validates :resource_id, presence: true
mount_uploader :path, PathUploader
validates :name, presence: true
# def self.abc
# params.permit(:name,:path)
# end
def initialize(params,file)
params=file[:name]
#params.permit(name =>:name,path =>:path)
end
end
undefined method `name' for #
You're referencing a non-existent attributes for your Post form:
<%= form_for #post,html: { multipart: true } do |f| %>
<%= f.label :title %><br>
<%= f.text_field :title %><br>
<br>
<%= f.label :body %><br>
<%= f.text_field :body %><br>
<%= f.submit %>
<% end %>
Remove :name & :path references.
--
If you want to pass "extra" attributes to another model, you need to use accepts_nested_attributes_for or set the params separately to your "primary" model:
#app/models/post.rb
class Post < ActiveRecord::Base
has_many :documents
accepts_nested_attributes_for :documents
end
#app/models/document.rb
class Document < ActiveRecord::Base
belongs_to :post
end
This will allow you to pass the documents as "nested" attributes of your Post model:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def new
#post = Post.new
#post.documents.build
end
def create
#post = Post.new post_params
#post.save
end
private
def post_params
params.require(:post).permit(:title, :body, documents_attributes: [:name, :path])
end
end
#app/views/posts/_form.html.erb
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body %>
<%= f.fields_for :documents do |d| %>
<%= d.text_field :name %>
<%= d.text_field :path %>
<% end %>
<%= f.submit %>
<% end %>
So undefined method on a model will indicate that, well, the method doesn't exist on the model. Want to see a model's methods? Post.methods. However, in this example, the column name is not defined on the model., and you're trying to tell Post that it has a name. What you need to do is nest your parameters.
While there is a ton of cleaning up that might want to focus on first, your answer is found in the accepts_nestable_attributes_for class methods, as shown here, http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html, and strong_params documentation as shown here, http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html
In your case, you want to create a new document from a post. Your permitted params hash will look like this,
params.require(:post).permit(:title, :body, :document_attributes => [:name])
Ensure that document_attributes is singular; if a person has_many pets (for example), then you'd have pets_attributes.
In your form, something that often trips people up is the builder.
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<%= f.fields_for #post.document do |document_field| %>
<%= document_field.text_field :name %>
<% end %>
<%= f.submit %>
<% end %>
Make sure that you're telling ERB that <%= f.fields_for %>, not just <% f.fields_for %>.

unable to create or update a belongs_to record in Rails 4

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.

Rails 4 strong params and nested form

I'm building a simple app (Ruby 2.0.0 and Rails 4) where a user can create a project and for each project create multiple screens. When creating a screen the user can upload a screenshot, that refer to a its own model (I do this to handle multiple versions of the same screen).
When creating the screen, the screenshot doesn't seem to be created because of a permission problem. Here's the server log:
Processing by ScreensController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"kezaGADsaLmY/+zozgbjEe5UfdeqRPg58FCf1qzfHxY=", "screen"=>{"project_id"=>"24", "name"=>"Billing", "description"=>"This is the page where a user will enter their credit card information", "screenshot"=>{"image"=># <ActionDispatch::Http::UploadedFile:0x007fcdce25b2c0 #tempfile=#<Tempfile:/var/folders/pv/srwrv0qj35b0hsxkt42l_z500000gn/T/RackMultipart20131007-91790-tewse9>, #original_filename="fb-banner.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"screen[screenshot][image]\"; filename=\"fb-banner.png\"\r\nContent-Type: image/png\r\n">}}, "commit"=>"Create Screen"}
Unpermitted parameters: screenshot
These are my models:
Screen
class Screen < ActiveRecord::Base
belongs_to :project
has_many :screenshots
validates :name, presence: true
accepts_nested_attributes_for :screenshots
end
Screenshot
class Screenshot < ActiveRecord::Base
belongs_to :screen
end
This is my screens_controller:
class ScreensController < ApplicationController
before_action :set_screen, only: [:show, :edit, :update, :destroy]
def index
#screens = Screen.all
end
def show
end
def new
#screen = Screen.new(:project_id => params[:project_id])
#screen.screenshot.build
end
def edit
end
def create
#screen = Screen.create(screen_params)
if #screen.save
flash[:notice] = "A new screen has been added to this project"
redirect_to [#screen.project]
else
render :action => 'new'
end
end
def update
#screen = Screen.find(params[:id])
if #screen.update_attributes(screen_params)
flash[:notice] = "The screen has been successfully updated"
redirect_to [#screen.project]
else
render :action => 'edit'
end
end
def destroy
#screen = Screen.find(params[:id])
#screen.destroy
flash[:notice] = "Successfully destroyed screen"
redirect_to [#screen.project]
end
private
def set_screen
#screen = Screen.find(params[:id])
end
def screen_params
params.require(:screen).permit(:project_id, :name, :description, screenshot_attributes: [ :id, :screen_id, :image, :version ])
end
end
And finally this is the form:
<%= form_for #screen, :html => { :multipart => true } do |f| %>
<% if #screen.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#screen.errors.count, "error") %> prohibited this screen from being saved:</h2>
<ul>
<% #screen.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.hidden_field :project_id %>
</div>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<%= f.fields_for :screenshot do |s| %>
<%= s.hidden_field :screen_id, :value => #screen.id %>
<%= s.hidden_field :version, :value => "1" %>
<%= s.label :image %><br>
<%= s.file_field :image %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I hope this is enough to help me spot the problem. I'm a newbie when it comes to programming, so any help is more than welcome.
I recently worked through something similar, and this is what seemed to work...
Change your fields_for to plural:
<%= f.fields_for :screenshots do |s| %>
And also, make your params
def screen_params
params.require(:screen).permit(:project_id, :name, :description, screenshots_attributes: [ :id, :screen_id, :image, :version ])
end
Also, you need to update your new action to make screenshots plural, like so:
def new
#screen = Screen.new(:project_id => params[:project_id])
#screen.screenshots.build
end

Resources