has_one :through - build_association undefined? - ruby

I have a Section model, where a Section can be a parent of another Section (subsection).
Here is my model:
class Section < ActiveRecord::Base
has_many :exercises
has_one :parent_link,
:foreign_key => 'subsection_id',
:class_name => 'SectionLink',
:dependent => :destroy
has_one :parent, :through => :parent_link
has_many :subsection_links,
:foreign_key => 'parent_id',
:class_name => 'SectionLink',
:dependent => :destroy
has_many :subsections, :through => :subsection_links
attr_accessor :parent_id
def to_param
"#{id}-#{description.parameterize}"
end
def self.search(search)
if search
find(:all, :conditions => ['description LIKE ?', "%#{search}%"])
else
find(:all)
end
end
end
And the association model:
class SectionLink < ActiveRecord::Base
belongs_to :parent, :class_name => 'Section'
belongs_to :subsection, :class_name => 'Section'
end
My controller:
class SectionsController < ApplicationController
# GET /sections
# GET /sections.json
def index
#sections = Section.order("subsections_count DESC").search(params[:search])
respond_to do |format|
format.html # index.html.erb
end
end
# GET /sections/1
# GET /sections/1.json
def show
#section = Section.find(params[:id])
#subsections = #section.subsections
#exercises = #section.exercises
respond_to do |format|
format.html # show.html.erb
format.json { render json: #section }
end
end
# GET /sections/new
# GET /sections/new.json
def new
#section = Section.new
#section.parent_id = params[:parent]
respond_to do |format|
format.html # new.html.erb
format.json { render json: #section }
end
end
# GET /sections/1/edit
def edit
#section = Section.find(params[:id])
end
# POST /sections
# POST /sections.json
def create
#section = Section.new(params[:section])
#parent = #section.build_parent(:parent_id => #section.parent_id) unless #section.parent_id.empty?
respond_to do |format|
if #section.save
format.html { redirect_to #section, notice: 'Section was successfully created.' }
format.json { render json: #section, status: :created, location: #section }
else
format.html { render action: "new" }
format.json { render json: #section.errors, status: :unprocessable_entity }
end
end
end
# PUT /sections/1
# PUT /sections/1.json
def update
#section = Section.find(params[:id])
respond_to do |format|
if #section.update_attributes(params[:section])
format.html { redirect_to #section, notice: 'Section was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #section.errors, status: :unprocessable_entity }
end
end
end
# DELETE /sections/1
# DELETE /sections/1.json
def destroy
#section = Section.find(params[:id])
#section.destroy
respond_to do |format|
format.html { redirect_to sections_url }
format.json { head :no_content }
end
end
end
The parent ID is fed in via a hidden field in the form:
<%= form_for(#section) do |f| %>
<% if #section.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#section.errors.count, "error") %> prohibited this section from being saved:</h2>
<ul>
<% #section.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :description %><br />
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<%= f.hidden_field :parent_id, :value => #section.parent_id %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I'm getting
undefined method 'build_parent' for #<Section:0xb4f1764c>
Is there a better way of modelling this association? Why is build_parent undefined?
UPDATE:
Now works with following controller code:
#section = Section.new(params[:section])
unless #section.parent_id.empty?
#parent = Section.find(#section.parent_id)
#section.parent = #parent
end
Looking for any suggestions on how it can be improved, and why it did not work before...

You're looking to do a self join.
class Section < ActiveRecord::Base
has_many :subsections, :class_name => "Section"
belongs_to :parent_section, :class_name => "Section",
:foreign_key => "parent_id"
end

Related

Where to permit a parameter in a has_one/belongs_to association?

When I try and edit the Contact to add a DataType, I receive a: 'Unpermitted parameter: data_format' error. I have tried following similar associations I have found online, but can't figure out what I am missing. I apologize if this is redundant.
Here are the relevant pieces of information:
Models:
# == Schema Information
#
# Table name: contacts
#
# id :integer not null, primary key
# name :string
# email :string
# phone :string
# mobile :string
# created_at :datetime not null
# updated_at :datetime not null
# supplier_id :integer
#
class Contact < ActiveRecord::Base
has_one :data_type
accepts_nested_attributes_for :data_type, allow_destroy: true
end
# == Schema Information
#
# Table name: data_formats
#
# id :integer not null, primary key
# name :string
# created_at :datetime not null
# updated_at :datetime not null
# contact_id :integer
#
class DataFormat < ActiveRecord::Base
belongs_to :contact
end
Contact Controller:
class ContactsController < ApplicationController
before_action :set_contact, only: [:show, :edit, :update, :destroy]
def new
#contact = Contact.new
end
def create
#contact = Contact.new(contact_params)
respond_to do |format|
if #contact.save
format.html { redirect_to #contact, notice: 'Contact was successfully created.' }
format.json { render :show, status: :created, location: #contact }
else
format.html { render :new }
format.json { render json: #contact.errors, status: :unprocessable_entity }
end
end
end
private
def set_contact
#contact = Contact.find(params[:id])
end
def contact_params
params.require(:contact).permit(:name, :email, :phone, :mobile, :data_format,
data_format_attributes: [ :id, :name, :contact_id, :_destroy ] )
end
end
Edit View:
<%= simple_form_for #contact do |f| %>
<div class="form-group">
<div class="col-lg-6">
<%= f.input :name %>
</div>
<div class="col-lg-6">
<%= f.simple_fields_for :data_format do |t| %>
<%= t.input :id, label: 'Date Format:', :collection => DataFormat.order(:name) %>
<% end %>
</div>
<div class="col-lg-6">
<%= f.label "Submit", class: 'control-label' %>
<%= f.button :submit, class: 'btn btn-primary form-control' %>
</div>
</div>
<% end %>
The DataType(s) are appearing in the form and I can select them. So, I know the issue must be within the controller.
Any help would be greatly appreciated!
Your contact.rb is accepting nested attributes name and permitted parameters name mismatch. contact.rb mentions: accepts_nested_attributes_for :data_type, allow_destroy: true .
contact.rb
class Contact < ActiveRecord::Base
has_one :data_format
accepts_nested_attributes_for :data_format, allow_destroy: true
end
contacts_controller.rb
class ContactsController < ApplicationController
before_action :set_contact, only: [:show, :edit, :update, :destroy]
def new
#contact = Contact.new
#contact.data_format = DataFormat.new
end
...
private
def set_contact
#contact = Contact.find(params[:id])
end
def contact_params
params.require(:contact).permit(:name, :email, :phone, :mobile, :data_format,
data_format_attributes: [ :id, :name, :contact_id, :_destroy ] )
end
form
<%= simple_form_for #contact do |f| %>
<div class="form-group">
<div class="col-lg-6">
<%= f.input :name %>
</div>
<div class="col-lg-6">
<%= f.simple_fields_for :data_format, #contact.data_format do |t|%>
<%= t.input :id, label: 'Date Format:', :collection => DataFormat.order(:name) %>
<% end %>
</div>
<div class="col-lg-6">
<%= f.label "Submit", class: 'control-label' %>
<%= f.button :submit, class: 'btn btn-primary form-control' %>
</div>
</div>
<% end %>

Email could not sent using Ruby on Rails 3?

I am trying to send one email through action mailer using ROR. But it can not sent even if it is not showing any error.I am explaining my codes below .Please check these and let me to know where i did mistake and what might be the possibility solutions.
views/users/_form.html.erb:
<%= 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 |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
views/user_mailer/registration_confirmation.html.erb:
Thank you for registering!
controller/users_controller.rb
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
UserMailer.registration_confirmation(#user).deliver
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
mailers/user_mailer.rb
class UserMailer < ActionMailer::Base
default from: "subhrajyotipradhan#gmail.com"
def registration_confirmation(user)
mail(:to => user.email, :subject => "Registered")
end
end
config/initializers/setup_mail.rb
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "gmail.com",
:user_name => "subhrajyotipradhan#gmail.com",
:password => "XXXXXXX",
:authentication => "plain",
:enable_starttls_auto => true
}
In your config/environments/<RAILS_ENV>.rb, alter or add the following configuration, and rerun your test:
config.action_mailer.delivery_method = :file
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
With this configuration, mails will not be actually delivered thru SMTP, but will be stored in tmp/mails/. If no error is raised, then check your SMTP settings.

Active Record Association not saving in database

I have two models:
class Tool < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :tools, dependent: :destroy
end
And I created a migration to provide the foreign key of the model:
class AddUserIdToTool < ActiveRecord::Migration
def change
add_column :tools, :user_id, :integer
end
end
I have the following form:
<%= form_for #tool, :html => { :multipart => true } do |f| %>
<% if #tool.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#tool.errors.count, "error") %> prohibited this tool from being saved:</h2>
<ul>
<% #tool.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.file_field :tool_image %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Whenever I submit the form the foreign key is not updated(user_id). I see the following while in my console:
irb(main):002:0> Tool.last
Tool Load (0.0ms) SELECT "tools".* FROM "tools" ORDER BY "tools"."id" DESC LIMIT 1
=> #<Tool id: 6, name: "wrench2", description: "another wrench", created_at: "2015-04-09 21:38:47", updated_at: "2015-04
-09 21:38:47", tool_image_file_name: "wrench.jpg", tool_image_content_type: "image/jpeg", tool_image_file_size: 3424, to
ol_image_updated_at: "2015-04-09 21:38:43", user_id: nil>
irb(main):003:0>
As you can see the user_id is nil
Here is my controller:
class ToolsController < ApplicationController
before_action :authenticate_user!, only: [:new, :destroy, :edit, :update], notice: 'you must sign in first!'
before_action :set_tool, only: [:show, :edit, :update, :destroy]
# GET /tools
# GET /tools.json
def index
#tools = Tool.all
end
# GET /tools/1
# GET /tools/1.json
def show
end
# GET /tools/new
def new
#tool = Tool.new
end
# GET /tools/1/edit
def edit
end
# POST /tools
# POST /tools.json
def create
#tool = Tool.new(tool_params)
respond_to do |format|
if #tool.save
format.html { redirect_to #tool, notice: 'Tool was successfully created.' }
format.json { render :show, status: :created, location: #tool }
else
format.html { render :new }
format.json { render json: #tool.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /tools/1
# PATCH/PUT /tools/1.json
def update
respond_to do |format|
if #tool.update(tool_params)
format.html { redirect_to #tool, notice: 'Tool was successfully updated.' }
format.json { render :show, status: :ok, location: #tool }
else
format.html { render :edit }
format.json { render json: #tool.errors, status: :unprocessable_entity }
end
end
end
# DELETE /tools/1
# DELETE /tools/1.json
def destroy
#tool.destroy
respond_to do |format|
format.html { redirect_to tools_url, notice: 'Tool was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_tool
#tool = Tool.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def tool_params
params.require(:tool).permit(:name, :description, :tool_image, :user_id)
end
end
How would I get the user_id updated with the id of the logged in user? Do I have to include a hidden field in my form or something like that?
Also do I have to permit the user_id variable within my strong parameters in my controller? I have tried this but it has not solved the problem...
How does this work?
Currently you are building a tool on its own. To associate it with the user model you need to create a tool model in the following way:
#user.tools.build
It will create a new ActiveRecord tool model with proper user_id of a belonged model. But to get parent you need to fetch its id from your params. It could be done in a such way, in your action:
#user = User.find(params[:user_id])
Note: to make it possible your routes should be nested correspondingly (read more here: http://guides.rubyonrails.org/routing.html)
So, all in all, your new action should look like:
def new
#user = User.find(params[:user_id])
#tool = #user.tools.build
end
And in your routes.rb
resources :users do
resources :tools
end

Nested Forms failing to save rails 4

I have a TodoList model and a TodoItem model. I can create the nested form and it renders in the todolist#new. It will only create a todolist title. It will accept the todo list items, but on the index page the items are not showing up.
I have done a ton of research including the docs and these sources; see bottom of the post.
The form will render with no errors. But when I hit save the todo list title will save, but the items I enter will not save.
Todo List Title
--This will save
Items
---This will not save
Controller
class TodoListsController < ApplicationController
before_filter :authenticate_user!
before_filter except: [:index]
before_action :set_todo_list, only: [:show, :edit, :update, :destroy]
# GET /todo_lists
# GET /todo_lists.json
def index
##todo_lists = TodoList.all
#todo_lists = current_user.todo_lists
#todo_items = current_user.todo_items
end
# GET /todo_lists/1
# GET /todo_lists/1.json
def show
end
# GET /todo_lists/new
def new
#todo_list = current_user.todo_lists.new
#todo_list.todo_items.build
respond_to do |format|
format.html # new.html.erb
format.json { render json: #todo_list }
end
end
# GET /todo_lists/1/edit
def edit
#todo_list = TodoList.find(params[:id])
end
# POST /todo_lists
# POST /todo_lists.json
def create
##todo_list = TodoList.new(todo_list_params)
#todo_list = current_user.todo_lists.new(todo_list_params)
respond_to do |format|
if #todo_list.save
format.html { redirect_to #todo_list, notice: 'Todo list was successfully created.' }
format.json { render :show, status: :created, location: #todo_list }
else
format.html { render :new }
format.json { render json: #todo_list.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /todo_lists/1
# PATCH/PUT /todo_lists/1.json
def update
#todo_list = TodoList.find(params[:id])
respond_to do |format|
if #todo_list.update(todo_list_params)
format.html { redirect_to #todo_list, notice: 'Todo list was successfully updated.' }
format.json { render :show, status: :ok, location: #todo_list }
else
format.html { render :edit }
format.json { render json: #todo_list.errors, status: :unprocessable_entity }
end
end
end
# DELETE /todo_lists/1
# DELETE /todo_lists/1.json
def destroy
##todo_list.TodoList.find(params[:id])
#todo_list.destroy
respond_to do |format|
format.html { redirect_to todo_lists_url, notice: 'Todo list was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def owns_todolist
if current_user != TodoList.find(params[:id]).user
redirect_to todo_lists_path, error: "You can't do that!"
end
end
# Use callbacks to share common setup or constraints between actions.
def set_todo_list
#todo_list = TodoList.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def todo_list_params
params.require(:todo_list).permit(:title,:todo_list => [:description])
end
end
Models
class TodoList < ActiveRecord::Base
has_many :todo_items, dependent: :destroy
accepts_nested_attributes_for :todo_items
end
class TodoItem < ActiveRecord::Base
belongs_to :todo_list
end
Form
<%= form_for(#todo_list) do |f| %>
<% if #todo_list.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#todo_list.errors.count, "error") %> prohibited this todo_list from being saved:</h2>
<ul>
<% #todo_list.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<%= f.fields_for :todo_items do |b| %>
<--- I also tried passing this in fields for #todo_list.todo_items.build -- >
<%= b.label :description, "Items" %><br />
<%= b.text_field :description %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Previous research
Nested Form with Nested Resource Rails 4
Rails 4 Nested Form.
How to Create Nested Forms in Rails 4
http://www.createdbypete.com/articles/working-with-nested-forms-and-a-many-to-many-association-in-rails-4/
http://railscasts.com/episodes/196-nested-model-form-revised?view=comments
Rails 4 Nested form fields not saving in database
And the list goes on.
The problem is with your todo_list_params method.It should be like this
def todo_list_params
params.require(:todo_list).permit(:title,todo_items_attributes: [:description])
end

Adding button click counter in rails 3

I want to add buttons on my article so that I can know the number of times its clicked and update counter on the database, I am using mongoid ,my model is:
class Article
include Mongoid::Document
include Mongoid::Timestamps
field :title, :type => String
field :content, :type => String
field :likes, :type => Integer ,:default => 0
field :dislikes, :type =>Integer, :default => 0
field :spam, :type => Integer, :default => 0
end
My articles show controller is:
def show
#article = Article.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #article }
end
end
My View for show is:
<p id="notice"><%= notice %></p>
<p>
<b>Title:</b>
<%= #article.title %>
</p>
<p>
<b>Content:</b>
<%= raw #article.content %>
</p>
Likes : <%= #article.likes %> <br/>
Dislikes : <%= #article.dislikes %><br/>
Spams : <%= #article.spam %><br/>
<%= link_to 'Edit', edit_article_path(#article) %> |
<%= link_to 'Back', articles_path %>
I find anything about it in internet.
How can I achieve it?
The easiest thing to do would be add a click_count integer attribute to your Article model and then increment this in your controller code:
def show
#article = Article.find(params[:id])
#article.increment! :click_count
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #article }
end
end
i got it done, phew!
I added the following form in my show.html.erb:
<%=form_for(#article,:action=>"update") do |f| %>
<%= submit_tag "Like", :name=>"like"%>
<%= submit_tag "Dislike",:name=>"dislike"%>
<%= submit_tag "Spam",:name=>"spam" %>
<%end%>
and wrote the following update controller:
def update
#article=Article.find(params[:id])
if params[:like]
#article.likes=#article.likes+1
elsif params[:dislike]
#article.dislikes=#article.dislikes+1
elsif params[:spam]
#article.spams=#article.spams+1
end
respond_to do |format|
if #article.update_attributes(params[:article])
format.html {redirect_to #article, :notice => "Article Updated"}
else
format.html {render :action=>"edit", :notice=> "Unable to update Article , sorry! :("}
end
end
end
It worked like a charm.

Resources