Rails has_one association setup - ruby-on-rails

Hi I'm new to rails and have been going in circles with this has_one association for hours. I have Products and Skins and when I create a new product via the form I'd like to use a select box to choose a skin to associate with the product.
I want to then render the product with a haml file in /skin/templates directory after having saved the name of the haml file in the templates column of the skins table.
The current error I'm getting is:
undefined method `template' for nil:NilClass
for this line in the controller:
render "/skins/templates/#{#product.skin.template}"
However I've tried other various configurations using skin_id as well and haven't been able to get past this.
Here's the code:
products_controller.rb
class ProductsController < ApplicationController
def show
#product = Product.find(params[:id])
if request.path != product_path(#product)
redirect_to #product, status: :moved_permanently
else
render "/skins/templates/#{#product.skin.template}"
end
end
def new
#product = Product.new
respond_to do |format|
format.html # new.html.haml
format.json { render json: #product }
end
end
def create
#product = Product.new(params[:product])
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render json: #product, status: :created, location: #product }
else
format.html { render action: "new" }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
end
product.rb
class Product < ActiveRecord::Base
attr_accessible :name, :skin
has_one :skin
end
skin.rb
class Skin < ActiveRecord::Base
attr_accessible :product, :name, :template
belongs_to :product
end
_form.html.haml
= form_for #product do |f|
- if #product.errors.any?
#error_explanation
%h1= "#{pluralize(#product.errors.count, "error")} prohibited this product from being saved:"
%ul
- #product.errors.full_messages.each do |msg|
%li= msg
.field
= f.label :name
= f.text_field :name
= f.select :skin_id, Skin.all.collect{|t| [t.name, t.id]}
.actions
= f.submit 'Save'
products table
id | name | created_at | updated_at
----+--------------+--------------------------------------------------------
1 | test | 2013-03-30 18:01:42.102505 | 2013-03-30 18:01:42.102505
skins table
id | name | template | created_at | updated_at | product_id
----+---------+----------+----------------------------+----------------------------+------------
1 | Product | product | 2013-03-30 20:13:26.374145 | 2013-03-30 20:13:26.374145 |

product_id in skin record is empty... but looks like your product should "belongs_to" skin
1) add skin_id to your products table and remove product_id from skins table
2) change Product model
class Product < ActiveRecord::Base
attr_accessible :name, :sku, :skin_id
belongs_to :skin
validates_presence_of :skin #add validation
end
3) Skin model
class Skin < ActiveRecord::Base
attr_accessible :name, :template
has_many :products
end

Related

Ruby on rails, Save data in two tables

I have a question.
I have this model:
class Project < ApplicationRecord
has_many :documents
belongs_to :course_unit
belongs_to :user
has_and_belongs_to_many :people
has_one :presentation
has_and_belongs_to_many :supervisors, :class_name => "Person", :join_table => :projects_supervisors
end
and this model:
class Presentation < ApplicationRecord
belongs_to :project
has_and_belongs_to_many :juries, :class_name => "Person", :join_table => :juries_presentations
end
When I create a new project, I have many attributes of the model Project and two attributes (room and date) from Presentation model, so I don't know how to send data from room and date attributes to the presentation model.
So my question is: How can I create a new project that saves data in project table and presentation table?
UPDATE #1
My project controller:
def new
#project = Project.new
end
def edit
end
def create
#project = Project.new(project_params)
#project.build_presentation
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render :show, status: :created, location: #project }
else
format.html { render :new }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #project.update(project_params)
format.html { redirect_to #project, notice: 'Project was successfully updated.'}
format.json { render :show, status: :ok, location: #project }
else
format.html { render :edit }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
private
def set_project
#project = Project.find(params[:id])
end
def project_params
params.require(:project).permit(:title, :resume, :github, :grade, :project_url, :date, :featured, :finished, :user_id, :course_unit_id, presentation_attributes: [ :date , :room ])
end
My index view for Projects is:
<%= form_for #project do |f| %>
<%= f.fields_for :presentations do |ff| %>
<%= ff.label :"Dia de Apresentação" %>
<%= ff.date_field :date %>
<%= ff.label :"Sala de Apresentação" %>
<%= ff.text_area :room %>
<% end
<%= f.submit %>
<% end %>
You can try something like this:
project = Project.new(name: 'project 1')
project.build_presentation(room: 'room 1', date: Time.current)
project.save
It will save project with name project 1 and presentation belongs to that project, with room room 1 and date is Time.current.
And you need to update your models to avoid presence validation.
class Project < ApplicationRecord
has_one :presentation, inverse_of: :project
end
class Presentation < ApplicationRecord
belongs_to :project, inverse_of: :presentation
end

Rails 4 controller actions for fields_for nested resources

I am trying to understand Rails' field_for, specifically what should go into the controller for nested resources. My issue is that when I create a comic with comic pages through the Comic form, the page's image are not saved.
I have Users, Comics, and ComicPages. Here are the models:
class User < ActiveRecord::Base
has_many :comics
has_many :comic_pages, through: :comics
end
class Comic < ActiveRecord::Base
belongs_to :user
has_many :comic_pages, :dependent => :destroy
accepts_nested_attributes_for :comic_pages
end
class ComicPage < ActiveRecord::Base
belongs_to :comic
end
Here is the form for Comic, where I also want to add comic_pages:
<%= form_for ([#user, #comic]) do |f| %>
<%= f.text_field :title %>
<%= f.fields_for :comic_pages do |comic_page| %>
<%= comic_page.file_field :comic_page_image %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I am confused about the comics_controller (new and create actions). How can I pass comic_page params to this controller???
def new
#user = current_user
#comic = #user.comics.new
#comic.comic_pages.build
end
def create
#user = current_user
#comic = #user.comics.new(comic_params)
#comic.comic_pages.build
respond_to do |format|
if #comic.save
format.html { redirect_to #user, notice: 'Comic was successfully created.' }
format.json { render action: 'show', status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #comic.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comic
#comic = Comic.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comic_params
params.require(:comic).permit(:title, :synopsis)
end
def comic_page_params
params.require(:comic_page).permit(:comic_page_image, :comic_image_file_name)
end
Many thanks!
--- EDIT ---
After the answer for the params, I used it to create the following create action:
def create
#user = current_user
#comic = #user.comics.new(comic_params)
i = 0
until i = 1
#comic_page = #comic.comic_pages.new(comic_params[:comic_pages_attributes]["#{i}"])
#comic_page.save
i += 1
end
respond_to do |format|
if #comic.save
...
end
end
end
You need to permit those fields from comic_pages that you want to save through in the comic_params section of your controller
params.require(:comic).permit(:title, :synopsis, comic_pages_attributes: [:comic_page_image])

Simple Rails Blog - Post Comments are ignoring Post ID [outside comment array in parameters]

I have a simple blog I'm building with Rails, and I'm following the normal rails getting started guide (http://guides.rubyonrails.org/getting_started.html). I'm setting up a form for comments inside my post's show method, but when I save, it's not saving the page_id in the comment record.
= form_for [#post, #post.comments.build], :remote => true do |f|
.field
= f.label :name
= f.text_field :name
.field
= f.label :extra_field, #page.rsvp_extra_field
= f.text_area :extra_field
.actions
= f.submit 'Save'
post.rb
class Post < ActiveRecord::Base
has_many :comments, dependent: :destroy
attr_accessible :comments_attributes, :comment_attributes
accepts_nested_attributes_for :comments, :allow_destroy => true
end
comment.rb
class Comment < ActiveRecord::Base
belongs_to :post
attr_accessible :extra_field, :name, :post_id, :phone
end
I see in the rails console that it's posting it, but putting NULL for post_id. Any thoughts?
EDIT
I didn't change my create method at all:
def create
#comment = Comment.new(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to post_url, notice: 'Comment was successfully created.' }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
EDIT 2
I think my parameters are nested when I don't want them to be... any ideas how to get this "post_id" inside of the "comment" array?
Parameters: {"utf8"=>"✓", "authenticity_token"=>"eqe6C7/ND35TDwtJ95w0fJVk4PSvznCR01T4OzuA49g=",
"comment"=>{"name"=>"test", "extra_field"=>""}, "commit"=>"Save", "post_id"=>"8"}
Because your method create in CommentsController, create object Comment unrelated to the object Post. has_many relation provide 3 methods for related objects:
post.comments.create
post.comments.create!
post.comments.build(eq new method)
Add in your CommentsController this:
...
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
end
...

Unknown attribute when linking two models together

Brief overview of my app.
It's quite basic in that the User first of all creates a set A client on one page and then uses another to create and assign jobs to the user.
My Client model and view are working as expected but im unable to link my jobs model.
Here is my jobs model.
class Client < ActiveRecord::Base
has_and_belongs_to_many :jobs
end
class Job < ActiveRecord::Base
has_and_belongs_to_many :clients
end
Here is also my clients controller.
class JobsController < ApplicationController
def index
#jobs = Job.find(:all)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #job }
end
end
def new
#jobs = Job.new
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #job }
end
end
def create
#jobs = Job.new(params[:job])
respond_to do |format|
if #jobs.save
format.html { redirect_to #jobs, notice: 'Job was successfully created.' }
format.json { render json: #jobs, status: :created, location: #jobs }
else
format.html { render action: "new" }
format.json { render json: #jobs.errors, status: :unprocessable_entity }
end
end
end
def show
#jobs = Job.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #jobs }
end
end
end
In my form I have two fields. One for the job name and another which is a drop down on all the clients listed in the database.
When fill this out however and I press save im getting the following error.
ActiveRecord::UnknownAttributeError in JobsController#create
**unknown attribute: client_id**
Application Trace | Framework Trace | Full Trace
app/controllers/jobs_controller.rb:22:in `new'
app/controllers/jobs_controller.rb:22:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"0ZVYpM9vTgY+BI55Y9yJDwCJwrwSgGL9xjHq8dz5OBE=",
"job"=>{"name"=>"Sample Monthly",
"client_id"=>"1"},
"commit"=>"Save Job"}
I have a junction table setup called clients_jobs also..
class AddClientsJobsTable < ActiveRecord::Migration
def up
create_table :clients_jobs, :id => false do |t|
t.belongs_to :job, :client
t.integer :client_id
t.integer :job_id
end
end
def down
drop_table :clients_jobs
end
end
I assume I need to declare client_id
somewhere but this is my first Rails app and im not sure where.
Any help would be greatly appreciated.
Edit: Here's my Job's form.
<%= simple_form_for :job do |f| %>
<%= f.input :name %>
<%= select("job", "client_id", Client.all.collect {|c| [ c.name, c.id ] }, {:include_blank => 'None'})%>
<%= f.button :submit %>
<% end %>
Your model states that job - client is a habtm association, but your form implements as if job belongs to (one) client. If indeed your intention is to be able to assign a job to multiple clients, your for should look something like:
<%= collection_select(:job, :client_ids, Client.all, :id, :name, {:include_blank => 'None'}, { :multiple => true }) %>
note plural 'client_ids' and allowing multiple in the input.
If a job belongs to only one user, you should not use has_and_belongs_to_many :clients.

Acces STI type on create view and controller

Hello guys I've a a 2 model client and meal.
client.rb
class Client < ActiveRecord::Base
has_many :meals
accepts_nested_attributes_for :meals
end
meal.rb
class Meal < ActiveRecord::Base
belongs_to :client
end
class Lunch < Meal
end
class Dessert < Meal
end
views/clients/_form.html.erb
<%= simple_form_for #client do |f| %>
<%=f.input :name %>
<%=f.input :adress %>
<%=f.input :telephone %>
<%= f.simple_fields_for :meal do |m| %>
<%=m.input :type %>
<%end%>
<% end %>
When I save the meal type it doesn't appear on client' index.html.erb(it's blank).
What the problem is?
How can I create a client by giving him a meal type(eg."Lunch") with the following cotroller:
def create
#client = Client.new(params[:client])
respond_to do |format|
if #client.save
format.html { redirect_to #client, notice: 'Operation was successfully created.' }
format.json { render json: #client, status: :created, location: #client }
else
format.html { render action: "new" }
format.json { render json: #client.errors, status: :unprocessable_entity }
end
end
end
Matter i simply have to set the column inheritance in meal.rb like this:
class Meal < ActiveRecord::Base
set_inheritance_column do
"type" + "_id"
end
belongs_to :client
end
class Lunch < Meal
end
class Dessert < Meal
end
So now I can select the type of meal when I create a client.
Thanks to Anan, the solution comes from him.

Resources