Follow user relationship - ruby-on-rails

I am implementing a follow feature for my users. For this, I followed instruction of micheal hartl tutorial link needed, yet I am getting this error:
undefined method id' for nil:NilClass <% if current_user.following?(#user) %>
this is my user model
has_many :relationships, foreign_key: "follower_id", dependent: :destroy
has_many :followed_users, through: :relationships, source: :followed
has_many :reverse_relationships, foreign_key: "followed_id",
class_name: "Relationship",
dependent: :destroy
has_many :followers, through: :reverse_relationships, source: :follower
def following?(user)
relationships.find_by(followed_id: user.id)
end
def follow!(user)
relationships.create!(followed_id: user.id)
end
def unfollow!(user)
relationships.find_by(followed_id: user.id).destroy
end
this is my relationship model
class Relationship < ActiveRecord::Base
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
validates :follower_id, presence: true
validates :followed_id, presence: true
end
and this is my view
<% if current_user.id && current_user.id != user.id %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= form_for(current_user.relationships.find_by(followed_id: #user.id),
html: { method: :delete }) do |f| %>
<%= f.submit "Unfollow", class:"unfollow-button" %>
<% end %>
<% else %>
<%= form_for(current_user.relationships.build(followed_id: #user.id)) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "Follow", class:"follow-button" %>
<% end %>
<% end %>
this is the user controller
def show
#user= User.find_by_slug(params[:id])
if #user
#posts= Post.all
render action: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
end
def index
#users = (current_user.blank? ? User.all : User.find(:all, :conditions => ["id != ?", current_user.id]))
end

This means #user is nil. Make sure that #user object is not null by doing
= debug #user
That should print all the details about #user object.

Related

Nested association has_many;through doesn't update collection_check_boxes

Using check boxes to update the nested form I can't update the tables. I received following message:
Unpermitted parameter: :category
ActionController::Parameters
{"name"=>"Flux Capacitor", "price"=>"19.55"} permitted: true
I have tried different ways to fix this through the permitted params, including a :category parameter, like so:
def product_params
params.require(:product).permit(:id, :name, :price, :category, categories_attributes: [:id, :name, :category], categorizations_attributes: [:id, :product_id, :category_ids, :category])
end
My models
class Product < ApplicationRecord
has_many :categorizations
has_many :categories, through: :categorizations
accepts_nested_attributes_for :categories, reject_if: proc {|attributes| attributes['name'].blank?}
accepts_nested_attributes_for :categorizations
end
class Categorization < ApplicationRecord
belongs_to :product, inverse_of: :categorizations
belongs_to :category, inverse_of: :categorizations
end
class Category < ApplicationRecord
has_many :categorizations
has_many :products, through: :categorizations, inverse_of: :category
end
class ProductsController < ApplicationController
def edit
#categories = Category.all
end
def new
#product = Product.new
end
def create
#product = Product.new(product_params)
if #product.save
flash[:notice] = 'Product succesfully created'
redirect_to products_path
else
flash[:notice] = 'Product was not created'
render 'edit'
end
end
def update
if #product.update(product_params)
flash[:notice] = "Product succesfully updated"
redirect_to products_path
else
flash[:notice] = 'Product was not updated'
render 'edit'
end
end
app/view/products/edit.html.erb
<%= simple_form_for(#product) do |f| %>
<%= f.input :name %>
<%= f.input :price %>
<%= f.simple_fields_for #product.categories do |cats| %>
<%= cats.collection_check_boxes :ids, Category.all, :id, :name, collection_wrapper_tag: :ul, item_wrapper_tag: :li %>
<% end %>
<%= f.button :submit %>
<% end %>
This seems like something that is common enough that rails and/or simple_form, should provide in a more built-in way to do this. Am I missing something obvious?
If I am understanding you correctly you should be able to do this without the use of accepts_nested_attributes_for or simple_fields_for. Try something like this:
<%= simple_form_for(#product) do |f| %>
<%= f.input :name %>
<%= f.input :price %>
<%= f.association :categories, as: :check_boxes %>
<%= f.button :submit %>
<% end %>
your strong params should look something like this:
def product_params
params.require(:product).permit(:id, :name, :price, { category_ids: [] }])
end

Having problems saving users' responses in quiz form

I'm trying to create an app where a user can click on a quiz and it will take them to the page where they can answer the quiz questions and submit their responses to a results page.
I'm having trouble saving the users' responses - it's either only saving the last records rather than all of them or not saving to the database at all.
Here is my code:
Question.rb:
belongs_to :quiz
has_many :answered_questions, dependent: :destroy
has_many :answers, dependent: :destroy
accepts_nested_attributes_for :answers, reject_if: :all_blank, allow_destroy: true
Answer.rb:
belongs_to :question
has_many :answered_questions, dependent: :destroy
User.rb:
has_many :answered_questions, dependent: :destroy
accepts_nested_attributes_for :answered_questions
AnsweredQuestion.rb:
belongs_to :user
belongs_to :question
belongs_to :answer
belongs_to :quiz
Quiz.rb
has_many :questions, dependent: :destroy
has_many :answered_questions, through: :questions, dependent: :destroy
accepts_nested_attributes_for :answered_questions, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :questions, reject_if: :all_blank, allow_destroy: true
quizzes_controller.rb:
class QuizzesController < ApplicationController
before_action :user_completed_quiz, only: [:show]
def show
#quiz = Quiz.find(params[:id])
#questions = Question.all
#answered_questions = current_user.answered_questions.build
#quiz.answered_questions.build
end
def create
#quiz = Quiz.new(show_params)
if #quiz.save
flash[:success] = "You have created a new quiz!"
redirect_to #quiz
else
render 'new'
end
end
def results
#quiz = Quiz.find(params[:id])
end
def post_answered_questions
#quiz = Quiz.find(params[:quiz][:id])
#answered_question = #quiz.answered_questions.build(show_params)
if #answered_question.save
flash[:success] = "You have completed the quiz!"
redirect_to results_quiz_path(params[:quiz][:id])
else
render ''
end
end
private
def user_completed_quiz
if(current_user.answered_questions.pluck(:quiz_id).uniq.include?(params[:id].to_i))
redirect_to quizzes_path
end
end
def show_params
params.require(:quiz).permit(:title, answered_questions_attributes: [:id, :answer_id, :question_id, :user_id, :quiz_id], questions_attributes: [:id, :question_title, :quiz_id, :done, :_destroy, answers_attributes: [:id, :answer_title, :question_id, :quiz_id, :correct_answer, :_destroy]])
end
end
show.html.erb - quizzes (where the form is):
<%= form_for(#answered_questions, url: answered_questions_path, method: "POST") do |f| %>
<%= #quiz.title %>
<%= f.hidden_field :id, :value => #quiz.id %>
<% #quiz.questions.each do |question| %>
<%= f.fields_for :answered_questions do |answer_ques| %>
<h4><%= question.question_title %></h4>
<%= answer_ques.hidden_field :question_id, :value => question.id %>
<%= answer_ques.hidden_field :quiz_id, :value => #quiz.id %>
<%= answer_ques.select(:answer_id, options_for_select(question.answers.map{|q| [q.answer_title, q.id]})) %>
<% end %>
<% end %>
<%= submit_tag %>
<% end %>

Rails 5 Has Many Through with Nested Form and Cocoon

Solverd: see bottom
I am building a ordering system of many products, with a HBTM from Join Table to anotherModel, but I have some problems when creating and editing a new record of a nested form.
I have tried many solutions from other questions and followed some tutorial like this or this, but nothing solved my issues.
Product Model:
class Product < ApplicationRecord
belongs_to :subcategory
has_many :order_products, inverse_of: :product
has_many :order, :through => :order_products
end
Order Model:
class Order < ApplicationRecord
has_many :order_products, inverse_of: :order
has_many :products, :through => :order_products
accepts_nested_attributes_for :products, reject_if: :all_blank, allow_destroy: true
end
Join Table:
class OrderProduct < ApplicationRecord
belongs_to :order
belongs_to :product
has_and_belongs_to_many :ingredients
accepts_nested_attributes_for :ingredients, reject_if: :all_blank, allow_destroy: true
end
Ingredients Model associated with join table: (many-to-many to save added ingredients to every products on the order)
class Ingredient < ApplicationRecord
has_and_belongs_to_many :order_products
end
Order Controller:
# GET /orders/new
def new
#order = Order.new
end
# GET /orders/1/edit
def edit
end
# POST /orders
# POST /orders.json
def create
#order = Order.new(order_params)
respond_to do |format|
if #order.save
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render :show, status: :created, location: #order }
else
format.html { render :new }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
def order_params
params.require(:order).permit(:subtotal, :discount, :total,
order_products_attributes: [[:id, :order_id, :product_id , :_destroy]])
end
Views:
<%= simple_form_for(#order) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :subtotal %>
<%= f.input :discount %>
<%= f.input :total %>
</div>
<%= f.simple_fields_for :order_products do |o| %>
<%= render 'order_product_fields', f: o %>
<% end %>
<%= link_to_add_association "aggiungi prodotto", f, :order_products %>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Partial: (unable to add cocoon's destroy link: undefined method `reflect_on_association' for NilClass:Class due to auto add of blank fields)
<div class="nested-fields order-product-fields">
<%= f.input :product %>
<%= f.input :order %>
<%= f.check_box :_destroy %>
</div>
I get this on console:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"PRNzrnxk/jrsAyPK5OzFxix2hIUmjCeWpD8Fkuhuhx8Wp3/xYTbTTvsfQkhnMDEBNnC/iNL46kl68XR7skb03g==", "order"=>{"subtotal"=>"", "discount"=>"", "total"=>"", "order_products"=>{"product"=>"", "order"=>"", "_destroy"=>"0"}}, "commit"=>"Create Order"}
Unpermitted parameter: order_products
My throubles are: EDIT: Solution on each point
When I load order pages, blanks fields for nested attributes are automatically created ()
Was wrong nested_attributes on Order Model:
accepts_nested_attributes_for **:order_products**, reject_if: :all_blank, allow_destroy: true
When submitting form no entry are created. (but I can add product to order via console .ex: order.products << product1)
When I add more product via cocoon's add link, only first is sent to controller
Don't know how to implements Strong Parameters and views for Ingredient's attributes inside the form of Order
Got this working:
Ingredient model:
has_many :ingredient_order_products, inverse_of: :ingredient
has_many :order_products, :through => :ingredient_order_products
IngredientOrderProduct model:
belongs_to :ingredient
belongs_to :order_product
Order Product model:
has_many :ingredient_order_products, inverse_of: :order_product
has_many :ingredients, :through => :ingredient_order_products
accepts_nested_attributes_for :ingredient_order_products, reject_if: :all_blank, allow_destroy: true
Order Controller:
def order_params
params.require(:order).permit(:customer_id, :subtotal, :discount, :total,
order_products_attributes: [[:id, :order_id, :product_id, :qty, :gift, :_destroy,
ingredient_order_products_attributes: [:id, :order_id, :ingredient_id, :_destroy]]])
end
_order_product_fields Partial:
<div id="ingredient">
<%= f.simple_fields_for :ingredient_order_products do |ingredient| %>
<%= render 'ingredient_order_product_fields', f: ingredient %>
<% end %>
<%= link_to_add_association "Aggiungi Ingrediente", f, :ingredient_order_products %>
</div>

ActiveRecord::RecordNotFound in RelationshipsController#create

I wanted to create twitter like followers and following thing.
in my view i have
<% if current_user.following?(#otheruser) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
in _follow.html.erb
<%= form_for (#otheruser), url: createfollower_path(#otheruser) ,:class=>"form-horizontal",method: :post do |f| %>
<%= f.hidden_field :user_id, :value => #otheruser.id %>
<%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
in controller create action
def create
user = User.find(params[:user_id])
current_user.follow(user)
redirect_to followuser_url
end
in user.rb
has_many :followers, class_name: "Relationship" #-> users following you
has_many :following, class_name: "Relationship", foreign_key: :follower_id, foreign_key: :user_id
def follow(other_user)
relationships.create(user_id: other_user.id)
end
in relationship.rb
class Relationship < ActiveRecord::Base
belongs_to :user
belongs_to :follower, class_name: "User"
validates :user, :follower, presence: true
validates :user_id, uniqueness: { scope: :follower_id }
end
now when I am trying to submit the follow button it is showing error as
"Couldn't find User with 'id'=" and parameters are
{"utf8"=>"✓","authenticity_token"=>"681q5ft03+WRdqgHagh/gI1mV3uohwaEj1sF8zdTycUAN5yTiVMT/wGCV4tLPRVRRFRA+6mYSS1bXk2ormA/zw==",
"user"=>{"user_id"=>"7"},
"commit"=>"Follow",
"format"=>"7"}
You need to rewrite your controller's create action.
def create
user = User.find(params[:user][:user_id])
current_user.follow(user)
redirect_to followuser_url
end
Should worked !!!

Skip validation when creating has_many :through records

In my db there are a lot of users with invalid data (without mobile number). Because I added mobile presence validation just now. When I'm trying to add new event, I get error messages "Users mobile number must be in ... format". How I can skip user validation when creating events?
event.rb
class Event < ActiveRecord::Base
has_many :participations
has_many :users, :through => :participations
end
user.rb
class User < ActiveRecord::Base
has_many :participations
has_many :events, :through => :participations
end
events_controller.rb
def create
#event = Event.new(event_params)
respond_to do |format|
if #event.save
format.html { redirect_to events_path, notice: 'Event was successfully created.' }
else
format.html { render action: 'new' }
end
end
end
_form.html.erb
<%= form_for #event, :html => {:class => 'row'} do |f| %>
<%= f.error_messages %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :user_ids, "Participants" %>
<%= f.collection_select :user_ids, User.all, :id, :name, {}, { :multiple => true } %>
<%= clear %>
<%= f.submit 'Save' %>
<% end %>
Set validate: false in Event has_many :users association
class Event < ActiveRecord::Base
has_many :participations
has_many :users, :through => :participations, validate: false
end

Resources