I've got a form with a nested one-to-one attribute which I can't save into the dabase. I've been reading SO threads for four hours to try and solve it:
Contact.rb:
class Contact < ApplicationRecord
has_one :address
accepts_nested_attributes_for :address
end
Address.rb
class Address < ApplicationRecord
belongs_to :contact
end
Routes.rb
Rails.application.routes.draw do
resources :contacts do
resources :addresses
end
root :to => 'contacts#index'
end
The form
<%= form_for #contact do |f| %>
<div class="field">
<%= f.label :firstname %>
<%= f.text_field :firstname %>
</div>
<div class="field">
<%= f.label :lastname %>
<%= f.text_field :lastname %>
</div>
<%= f.fields_for :address do |address_fields| %>
<%= address_fields.label :streetname %>
<%= address_fields.text_field :streetname %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Controller:
class ContactsController < ApplicationController
before_action :find_contact, only: [:show, :edit, :update, :destroy]
def index
#contacts = Contact.all
end
def show
end
def new
#contact = Contact.new
#ontact.build_address
end
def create
#contact = Contact.new(contact_params)
if #contact.save
redirect_to #contact
else
render 'new'
end
end
(...)
private
def find_contact
#contact = Contact.find(params[:id])
end
def contact_params
params.require(:contact).permit(:firstname, :lastname,
address_attributes: [:contact_id, :streetname])
end
end
With the above code, nothing is saved and the transaction is rolled back. Earlier on, only the contact-details were saved whereas the address remained nil and the following line gave an error that "streetname" was unknown:
<p><%= #contact.address.streetname %></p>
Your help is much appreciated!
Thanks #fbelanger for leading me to the solution:
I noticed from the contents of "params" that permitted was set on false. I found via Google that Rails 5 requires the following addition in the address model, to the belongs_to line:
class Address < ApplicationRecord
belongs_to :contact, required: false
end
And now it's saved: hurray!
Related
I am building a method in which users can review other users and I am using https://github.com/mackenziechild/movie_review as a base
views/profiles/show
<%= link_to "Write a Review", new_user_review_path(#user) %>
views/review/._form
<%= form_for([#user, #review]) do |f| %>
<div class="field">
<div id="star-rating"></div>
</div>
<div class="field">
<%= f.label :comment %><br>
<%= f.text_area :comment %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
class Review < ApplicationRecord
belongs_to :user
end
class ReviewController < ApplicationController
before_action :authenticate_user!
def new
#review = Review.new
end
def create
#review = Review.new(review_params)
#review.user_id = current_user.id
#review.receiver_id=#user.id
#review.save
end
private
def set_review
#review = Review.find(params[:id])
end
def review_params
How do I solve this?
Routes
user_review_index_path POST /users/:user_id/review(.:format)
review#create
new_user_review_path GET /users/:user_id/review/new(.:format)
review#new
Routes.rb
resources :users do
resources :review, only: [:new, :create]
end
hmm, maybe I have to do a member do?
Edit, I was playing around with it, I think it's because the model being reviewed is not being set properly in the controller
def set_receiver
#review.receiver = User.find(params[:receiver_id])
end
Adding something like this gives me a "no resource found" error
How do I set the receiver of the review since it's another user?
I am trying to create a rating for a particular teacher. I already added the school_id into my ratings table, but still get the error:
No route matches {:action=>"show", :controller=>"teachers",
:id=>"teacher_id", :school_id=>nil} missing required keys:
[:school_id]
redirect_to school_teacher_path(params[:school_id], [:teacher_id])
Here is my route file, routes.rb:
Rails.application.routes.draw do
resources :schools do
resources :teachers
end
resources :teachers do
resources :ratings
end
ratings_controller.rb:
class RatingsController < ApplicationController
def new
get_teacher
#rating = #teacher.ratings.build
end
def create
get_teacher
#rating = #teacher.ratings.build(rating_params)
if #rating.save
redirect_to school_teacher_path(params[:school_id], [:teacher_id])
else
render 'new'
end
end
def get_teacher
#teacher = Teacher.find(params[:teacher_id])
end
private
def rating_params
params.require(:rating).permit(:easiness, :helpful, :clarity, :comment,
:teacher_id, :school_id)
end
end
ratings/new.html.erb:
<h1>Teacher Rating</h1> <%= form_for([#teacher, #rating]) do |f| %> <p>
<%= f.label :clarity %>
<%= f.text_field :clarity %> </p>
<p>
<%= f.label :easiness %>
<%= f.text_field :easiness %> </p>
<p>
<%= f.label :helpfulness %>
<%= f.text_field :helpfulness %> </p>
<p>
<%= f.label :comment %>
<br>
<%= f.text_area :comment %> </p>
<p>
<%= f.submit %> </p> <% end %>
rating.rb:
class Rating < ActiveRecord::Base
belongs_to :teacher, dependent: :destroy
end
teacher.rb:
class Teacher < ActiveRecord::Base
belongs_to :school
has_many :ratings
def name
"#{firstName} #{middleName} #{lastName}"
end
def to_s
name
end
end
school.rb:
class School < ActiveRecord::Base
has_many :teachers, dependent: :destroy
validates :name, presence: true,
length: { minimum: 5 }
end
In this line:
redirect_to school_teacher_path(params[:school_id], [:teacher_id])
You are passing the params[:school_id] variable, and then an array containing the symbol :teacher_id.
I suspect you really intended to use something like this:
redirect_to school_teacher_path(params[:school_id], params[:teacher_id])
I have a many_to_many association between Articles and Categories, using has_and_belongs_to_many in a Rails 4 app:
Here are the corresponding migration and classes:
class CategoriesArticles < ActiveRecord::Migration
def change
create_table :articles_categories, id: false do |t|
t.belongs_to :category, index: true
t.belongs_to :article, index: true
end
add_index :articles_categories, [:category_id, :article_id]
end
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :articles
end
class Article < ActiveRecord::Base
has_and_belongs_to_many :categories
end
When a user creates a new article, I simply want to give him or her the option to select categories that he/she wants to associate with the new article. I want the user to be able to select these categories with checkboxes.
Here's the ArticlesController:
class ArticlesController < ApplicationController
before_action :set_article, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, only: [:new, :create, :edit, :destroy, :update]
before_action :verify_own_article, only: [:destroy]
respond_to :html
...
def new
#categories = Category.all
#article = Article.new
respond_with(#article)
end
def create
# Creates article object with current_user_id, initial_comment, and URL
#article = current_user.articles.build(article_params)
# Uses Pismo (gem) to grab title, content, photo of URL
#article.populate_url_fields
if #article.save
flash[:success] = "Article created!"
# Might need to change the location of this redirect
redirect_to root_url
else
flash[:notice] = "Invalid article."
redirect_to new_article_path
end
end
def update
#article.update(article_params)
flash[:notice] = "Article successfully updated."
respond_with(#article)
end
private
def set_article
#article = Article.find(params[:id])
end
def article_params
params.require(:article).permit(:url, :title, :datetime, :content, :photo, :initial_comment)
end
# Ensure that a signed in user can only delete articles that they have posted
def verify_own_article
#article = current_user.articles.find_by_id(params[:id])
end
end
Here's the article new.html.erb view:
<h1>New article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
... and the form partial:
<%= form_for(#article) do |f| %>
<% if #article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#article.errors.count, "error") %> prohibited this article from being saved:</h2>
<ul>
<% #article.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :url %><br>
<%= f.text_field :url %>
</div>
<div class="field">
<%= f.label :initial_comment %><br>
<%= f.text_field :initial_comment %>
</div>
<% #categories.each do |t| %>
<div class="field">
<%= f.label t.name %>
<%= f.check_box "categories[#{t.id}]" %>
<br />
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
However, this is erroring for me, specifically the lines:
<% #categories.each do |t| %>
<div class="field">
<%= f.label t.name %>
<%= f.check_box "categories[#{t.id}]" %>
<br />
</div>
<% end %>
Specifically, it's telling me:
undefined method 'categories[1]' for #<Article:0x007f401193d520> when I try to render the New Article page. How do I fix this? Thanks.
It is better to use Rails collection_check_boxes helper instead of trying to create those checkboxes by hand. This helper already creates all the parameter / markup stuff you need in order to add or exclude items of a HABTM relation, all under the hood. So you might change you view to include the following:
<%= f.collection_check_boxes :categories_ids, #categories, :id, :name %>
Don't forget to add this in your strong parameters declaration (since you'll have to receive the selected categories ids and bind them to your Article model):
params.require(:article).permit(
:url, :title, :datetime, :content,
:photo, :initial_comment, categories_ids: []
)
For further customizations (html styling or structure for each checkbox), please refer to the complete documentation
I hope it helps :)
<center><h1> welcome </h1></center>
<%= form_for :authors , url: auth_path do |f| %>[this is the controller auth and model author]
<p>
<%= f.label :title %><br>
<%= f.text_field :topic %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :content ,:cols => "30", :rows => "10" %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
the error is
ActionController::UrlGenerationError in Auth#new
[controller code check it is right or not]
i have tried for it but nothing works
can any one correct the code
class AuthController < ApplicationController
def index
#author = Author.all
end
def show
#author = Author.find(params[:id])
end
def new
end
def create
#author = Author.find(params[:id])
#auth = #author.comments.create(comment_params)
redirect_to #author
end
private
def author_params
params.require(:author).permit(:topic, :content)
end
end
In controller define method same name as this page name in that get #author = Author.find(params[:id]) and in view
<%= form_for #author, :as => :author, :url => auth_path(#author) do |f| %>
And to use single model for multiple controller
class User::AuthorsController < ApplicationController
def welcome
end
end
or
module User
class AuthorsController < ApplicationController
def welcome
end
end
end
You can also call your partials this way
render :template => "user/authors/welcome"
Then in routes.rb
namespace :user do
resources :authors
end
I have a serialized object :address in Hotel model and I don't know how to save it properly in the DB. I have the following:
#model hotel
class Hotel < ActiveRecord::Base
belongs_to :user
serialize :address, Hash
end
...and view 'new'
<%= form_for(#hotel) do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :stars %>
<%= f.text_field :stars %>
<%= f.label :room, "Room description" %>
<%= f.text_area :room, size: "20x10" %>
<%= f.label :price %>
<%= f.number_field :price %>
<%= f.fields_for :address do |o| %>
<%= o.label :country %>
<%= o.text_field :country %>
<%= o.label :state %>
<%= o.text_field :state %>
<%= o.label :city %>
<%= o.text_field :city %>
<%= o.label :street %>
<%= o.text_field :street %>
<% end %>
<%= f.submit "Create hotel", class: "btn btn-large btn-primary" %>
<% end %>
With this code what I get is: hotel address nil...
Okay.. We will go another way. After googling much I came to this code:
# hotel.rb model
class Hotel < ActiveRecord::Base
class Address
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :country, :state, :city, :street
def persisted?; true end
def id; 1 end
def self.load json
obj = self.new
unless json.nil?
attrs = JSON.parse json
obj.country = attrs['country']
obj.state = attrs['state']
obj.city = attrs['city']
obj.street = attrs['street']
end
obj
end
def self.dump obj
obj.to_json if obj
end
end
belongs_to :user
serialize :address, Address
end
and the same view new.html.erb
The result is: Address:0xb0e530c
So, nothing saves in the database... I don't know what to try next, I'll appreciate any help. Didn't know that serialized object will cause so much problems to me.
THANKS!
PS Here's hotels_controller.
class HotelsController < ApplicationController
before_action :signed_in_user, only: [:index, :edit, :update, :destroy]
def new
#hotel = Hotel.new
end
def index
#hotels = Hotel.paginate(page: params[:page])
end
def show
#hotel = Hotel.find(params[:id])
end
def create
#hotel = current_user.hotels.build(hotel_params)
if #hotel.save
flash[:success] = "Hotel created!"
redirect_to #hotel
else
render 'new'
end
end
private
def hotel_params
params.require(:hotel).permit(:title, :stars, :room, :price, :address)
end
end
First thing on your migration file make sure that you are saving your fields as a test like
def self.up
add_column : hotels, : address, :text
end
Then Rails will convert it into YAML / Hash for you (and perform proper serialization).
Wish you the best of luck.
PS take a look at https://stackoverflow.com/a/6702790/1380867