has_many build method, Rails - ruby-on-rails

Another newbie question.
The goal: each ingredient can have zero or more unit conversions tied to it. I want to put a link to creating a new unit conversion on the page that shows a specific ingredient. I can't quite get it to work.
Ingredient Model:
class Ingredient < ActiveRecord::Base
belongs_to :unit
has_many :unit_conversion
end
Unit Conversion Model:
class UnitConversion < ActiveRecord::Base
belongs_to :Ingredient
end
Unit Conversion Controller (for new)
def new
#ingredient = Ingredient.all
#unit_conversion = #ingredient.unit_conversions.build(params[:unit_conversion])
if #unit_conversion.save then
redirect_to ingredient_unit_conversion_url(#ingredient, #comment)
else
render :action => "new"
end
end
Relevant Routes:
map.resources :ingredients, :has_many => :unit_conversions
Show Ingredient Link:
<%= link_to 'Add Unit Conversion', new_ingredient_unit_conversion_path(#ingredient) %>
This is the error:
NoMethodError in Unit conversionsController#new
undefined method `unit_conversions' for #<Array:0x3fdf920>
RAILS_ROOT: C:/Users/joan/dh
Application Trace | Framework Trace | Full Trace
C:/Users/joan/dh/app/controllers/unit_conversions_controller.rb:14:in `new'
Help! I'm all mixed up about this.

Unit Conversion Controller for new and create should be:
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
Also, this screencast is a nice resource for nested resources.

has_many :unit_conversion
Should be pluralized since you're calling it with
#unit_conversion = #ingredient.unit_conversions.build
your controller
def new
#ingredient = Ingredient.all
should be calling #new to setup a new Ingredient or #find to grab an existing Ingredient.
#ingredient = Ingredient.new # returns a new Ingredient
or
#ingredient = Ingredient.find(...) # returns an existing Ingredient
Which one you choose is up to your requirements.
Also, this is a typo, right?
belongs_to :Ingredient
You might want to lowercase :ingredient

Related

Duplicate two linked models Ruby

I want to duplicate my models 'Formulaire' and 'Question'. They have a has_may/belongs_to relation.
I'm able to duplicate the first model but I have a " NoMethodError in FormulairesController#duplicate
undefined method `save' for # " when I duplicate the second
My models :
Formulaire.rb
class Question < ActiveRecord::Base
belongs_to :formulaire
validates :nom, presence: true
end
Question.rb
class Formulaire < ActiveRecord::Base
has_many :questions, dependent: :destroy
end
formulaire_controller.rb
def duplicate
template = Formulaire.find(params[:id])
#formulaire= template.dup
#formulaire.save
#for question in #formulaire.questions
# question.dup
# question.save
#end
template2 = Question.where(formulaire_id: 47)
#question = template2.dup
#question.save
redirect_to #formulaire, notice: "Formulaire dupliqué"
end
def formulaire_params
params.require(:formulaire).permit(:name, :description,
questions_attributes: [:id, :nom, :typequestion, :image, '_destroy', photos_attributes:[:id],
answers_attributes:[:id, :content,'_destroy']]) if params[:formulaire]
#puts YAML::dump params
end
My view
formulaire/show.html.erb
<li class="Dupliquer"><%= link_to 'Dupliquer', duplicate_formulaire_path(#formulaire) %> </li>
routes.rb
resources :formulaires do
member do
get 'duplicate'
end
end
Thank you
Here in stackoverflow, I found it here:
If you want to copy an activeRecord object you can use its attributes to create new one like
you can have an action in your controller which can be called on link,
def create_from_existing
#existing_post = Post.find(params[:id])
#create new object with attributes of existing record
#post = Post.new(#existing_post.attributes)
render "your_post_form"
end
what's here: Rails clone copy or duplicate
I never used this gem, but it's for this, I'm going to leave it there and you'll see what you want.
https://github.com/amoeba-rb/amoeba
And also on reddit
def clone
#location = Location.find(params[:id]).dup
............
render :new
end
link: https://www.reddit.com/r/rails/comments/6phfy4/form_how_to_implement_a_clone_action/

Ruby on Rails - Pass ID from another controller

I have two models. First is Taxirecord and second is Carpark. Each Taxirecord may have its own Carpark. I have a problem with passing taxirecord_id to Carpark record. I have route
car_new GET /taxidetail/:taxirecord_id/carpark/new(.:format) carparks#new
And i want to pass :taxirecord_id, which is id of taxirecord that im editing, to my create controller.
My carpark model:
class Carpark < ActiveRecord::Base
belongs_to :taxirecord
end
In controller im finding taxirecord_id by find function based on param :taxirecord_id, but id is nil when create is called. Can you please help me to find out what Im doing wrong and how Can I solve this problem? Thanks for any help!
My carpark controller
class CarparksController < ApplicationController
def new
#car = Carpark.new
end
def create
#car = Carpark.new(carpark_params, taxirecord_id: Taxirecord.find(params[:taxirecord_id]))
if #car.save
flash[:notice] = "Zaznam byl ulozen"
redirect_to root_path
else
flash[:notice] = "Zaznam nebyl ulozen"
render 'new'
end
end
private def carpark_params
params.require(:carpark).permit(:car_brand, :car_type, :driver_name, :driver_tel)
end
end
I finally get it work
Ive added <%=link_to 'New Carpark', {:controller => "carparks", :action => "new", :taxirecord_id => #taxi_record.id }%>
to my taxirecord form and to carpark form <%= hidden_field_tag :taxirecord_id, params[:taxirecord_id] %>
And to my carpark controller : #carpark.taxirecord_id = params[:taxirecord_id]
Thanks everyone for great support and help!
I'd lean towards using something like:
before_action :assign_taxirecord
...
private
def assign_taxirecord
#taxirecord = TaxiRecord.find(params[:taxirecord_id])
end
And then in the create action:
def create
#car = #taxirecord.build_carpark(carpark_params)
...
end
Obviously there's a little tailoring needed to your requirements (i.e. for what actions the before_action is called), but I hope that helps!
No need to send taxirecord id.
class Carpark < ApplicationRecord
belongs_to :taxirecord
end
class Taxirecord < ApplicationRecord
has_one :carpark
end
Rails.application.routes.draw do
resources :taxirecords do
resources :carparks
end
end
for new taxirecord
t = Taxirecord.new(:registration => "efgh", :description =>"test")
for new carpark
t.create_carpark(:description=>"abcd")
#=> #<Carpark id: 2, taxirecord_id: 2, description: "abcd", created_at: "2017-10-12 10:55:38", updated_at: "2017-10-12 10:55:38">

How can I capture an instance generically?

I'm using Rails 3.2.19 and Ruby 2.1.2. I've been googling around trying to figure this out, but perhaps I'm not searching for the right thing. Anyway, I'll try and be as concise as possible.
I have a few different models that all have a name attribute. In my views I want to somehow be able to access that name attribute regardless of the instance name passed into the view. Currently my various controllers create instances of their respective models. For instance:
class PagesController < ApplicationController
def show
#page = Page.find(params[:id])
respond_to do |format|
format.html
end
end
end
-
class ProductsController < ApplicationController
def show
#product = Product.find(params[:id])
respond_to do |format|
format.html
end
end
end
While I understand I could simply re-name the instances something generic, I was wondering if there was some way of accessing any/all instances while maintaining unambiguous instance names.
Basically something like this:
page.html.haml
%h1= resources[0].name #equates to #page.name
%h2= #page.some_other_attribute
or
product.html.haml
%h1= resources[0].name #equates to #product.name
%h2= #product.price
Where in each of the above resources[0] would be either #page or #product
You will have to define a route with an additional resource_type parameter to a generic controller or otherwise just include the resource_type into the url query parameter
/resources/product/17
or
/resources/17?resource_type=product
This will allow you to do the following in the controller
class ResourcesController < ApplicationController
def show
#resource = find_resource(params)
respond_to do |format|
format.html
end
end
private
def find_resource(params)
resource_klass = {
product: Product,
page: Page
}[params[:resource_type]]
resource_klass.find(params[:id])
end
end
Another Option would be to introduce another ResourceType Entity and define a polymorphic :has_one :belongs_to association to the actual resource entity (product, page). Then always search for ResourceTypes and load the polymorphic resource entity
class ResourceType < ActiveRecord::Base
belongs_to :resource, polymorphic: true
end
class Product < ActiveRecord::Base
has_one :resource_type, as: :resource
end
class Page < ActiveRecord::Base
has_one :resource_type, as: :resource
end
product_resource_type = ResourceType.create(...)
product = Product.create(resource_type: product_resource_type)
page_resource_type = ResourceType.create(...)
page = Page.create(resource_type: page_resource_type)
ResourceType.find(product_resource_type.id).resource
=> product
ResourceType.find(page_resource_type.id).resource
=> page
I figured this out after discovering instance_variables and instance_variables_get
Those methods will return all instance variables being passed into the view. From there I discovered that the :#_assigns instance variable contained the instances that I was looking for. So I iterated over them to find if any had the name attribute.
- instance_variable_get(:#_assigns).each do |var|
- if var[1].respond_to?("name")
%h1= var[1].name
There is probably a better way of accomplishing this, so if anyone has any opinions, they are welcome.

Rails 4.0.2 ActionController::ParameterMissing in AuctionsController#create param not found:

I am creating an auction website and I get an error when I run a command to create a new auction.
The model is simple:
class Auction < ActiveRecord::Base
has_many :bets
has_many :profiles, :through => :bets
and etc.
The controller: `
class AuctionsController < ApplicationController
def new
#auction = Auction.new
end
def create
#auction = Auction.new(auction_params)
if #auction.save
redirect_to(:action => 'index')
else
render('new')
end
end
private
def auction_params
params.require(:auction_email).permit(:auction_description, :auction_location, :auction_deadline, :auction_title, bets_attributes: [ :bet_size], )
end
end
The new.html.erb has form in this way:
<%= form_for(:auction, :url => {:action => 'create'}) do |f| %>
<%= f.text_field(:auction_title) %>
and so on for every entry.
The error message is:
ActionController::ParameterMissing in AuctionsController#create param not found: auction_email
I have been trying to solve it with "if params[:status]", but it returns an empty form and database remains empty.
Rails version 4.0.2
Use this
def auction_params
params.require(:auction).permit(:auction_email,:auction_description, :auction_location, :auction_deadline, :auction_title, bets_attributes: [ :bet_size], )
end
Assuming that Auction is your model.
params.require argument should be :auction(:modelname) and in permit method you pass the atrributes like :auction_email(:attributename) that you would like to insert/update in database.

Rails: submit form with nested attributes throws 'couldn't find entity with id=xxx'

I got the following model classes:
class Movie < ActiveRecord::Base
has_and_belongs_to_many :actors
accepts_nested_attributes_for :actors, :allow_destroy => true
...
end
and
class Actor < ActiveRecord::Base
has_and_belongs_to_many :movies
...
end
movies/_form.html.haml view contains the nested form for actors:
...
= form_for #movie do |movie_form|
= movie_form.fields_for :actors do |actor_form|
= actor_form.text_field :id, "Id"
= link_to_remove_fields "remove", actor_form
= link_to_add_fields movie_form :actors
...
= movie_form.submit 'Save'
link_to_remove_fields and link_to_add_fields are helper methods performing javascript calls, adding new fields for new actors or removing actors.
The controller:
class MovieController < ApplicationController
#POST form
def create
#movie = Movie.new(params[:movie])
...
end
#GET nearly empty form with one field for actor
def new
#movie = Movie.new
1.times {#movie.actors.build}
respond_to do |format|
format.html
format.json { render json: #movie }
end
end
end
The problem:
When 'Save' is pressed (with only one actor with id=718, for example) and the form is submitted, the #movie = Movie.new(params[:movie]) line of the controller throws the following error:
Couldn't find Actor with ID=718 for Movie with ID=
I'm sure that there is entity with id=718 in the Actor database.
The easiest thing if you are trying to associating existing actors to a new movie is not to use accepts_nested_attributes at all.
One of the things you get with your actors associations is a actor_ids, which return the ids of the associated actors, or allows you to set the list of associated actors.
To submit an array via a rails form, the name of the input must end with [], for example if you have an input with name movie[actor_ids][] and value 1, then you'll get
{'movie' => {'actor_ids' => ['1']}}
in your controller. If you want to submit a second actor, just create another input with the same name movie[actor_ids][]. You could also use a select box with the multiple attribute set, but they can be a bit unfriendly for users especially when there are more than just a few options to pick from.
Unfortunately you can't use accepts_nested_attributes_for with has_and_belongs_to_many (see Trying to use accepts_nested_attributes_for and has_and_belongs_to_many but the join table is not being populated for example). You would probably be able to build something similar with a network of has_many :x through: :ys though.

Resources