I want to add an adress to gym and that gym only have one adress, so also i have users that can have many adresses, cause that i want to use polymorphic relations for adresses but the fields_for it's not shown
Models
# Adress model
class Adress < ApplicationRecord
include AdressTypeAsker
belongs_to :adressable, polymorphic: true
end
# Gym model
class Gym < ApplicationRecord
belongs_to :user
has_one :adress, as: :adressable
accepts_nested_attributes_for :adress
end
# User model
class User < ApplicationRecord
include UserTypeAsker
include UserAdressType
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
has_many :adresses, as: :adressable
accepts_nested_attributes_for :adresses
has_many :gyms
end
Gym Controller
class GymsController < ApplicationController
def index
if current_user.is_manager?
#gym = current_user.gyms.new
#gym.adress
end
end
def create
if current_user.is_manager?
#gym = current_user.gyms.new(gym_params)
#gym.save!
redirect_to gyms_path
else
redirect_to gym_path
end
end
private
def gym_params
params.require(:gym).permit(:name, :open, :close, adress_attributes: [:name, :longitude, :latitude])
end
end
Nested form
= form_for #gym do |f|
.col.s6
= f.label :open
= f.time_field :open, class: "timepicker"
.col.s6
= f.label :close
= f.time_field :close, class: "timepicker"
.col.s12
= f.label :name
= f.text_field :name
.col.s12
= f.fields_for :adress do |adress_form|
= adress_form.label :name, "adress name"
= adress_form.text_field :name
= adress_form.label :longitude
= adress_form.text_field :longitude
= adress_form.label :latitude
= adress_form.text_field :latitude
= f.submit "Add home adress", class: "waves-effect waves-teal btn-large gymtoy-primary z-depth-0"
Migration
class AddAdressToGyms < ActiveRecord::Migration[5.1]
def change
add_column :adresses, :adressable_id, :integer, index: true
add_column :adresses, :adressable_type, :string
end
end
you new to build address for gym, so modify index action as
def index
if current_user.is_manager?
#gym = current_user.gyms.new
#gym.build_adress
end
end
OR
modify fields_for as
= f.fields_for :adress, #gym.adress || #gym.build_adress do |adress_form|
Related
I have three tables: books, comments and users. Tables are related. Users can login and then comment on books. Users have a dashboard. How can I make users see the comments that have been made to their books on their dashboard?
Here are the models,
book.rb:
class Book < ApplicationRecord
validates :title, presence: true
validates :author, presence: true
belongs_to :user
has_many :comments
end
comment.rb:
class Comment < ApplicationRecord
belongs_to :book
belongs_to :user
scope :approved, -> {where(status: true)}
end
user.rb:
class User < ApplicationRecord
before_create :set_username
has_many :books
has_many :comments
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
attr_writer :login
def login
#login || self.username || self.email
end
# validates_length_of :username,
# :within => 5..50,
# :too_short => " is too short, must be at least 5 characters.",
# :presence => true
private
def set_username
self.username = self.email.split("#").first
end
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
else
if conditions[:username].nil?
where(conditions).first
else
where(username: conditions[:username]).first
end
end
end
end
dashboard controller:
class DashboardController < ApplicationController
def index
#books = current_user.books
end
end
Since you already have the book, you can also include the comments to reduce n+1. So in your DashboardController you can modify the statement you have with #books = current_user.books.includes(:comments). This will collect all of the comments for that user's books. Then in the view you can iterate through them like this. Where you can display them however you want, ie, ol/ul with children li for teh comments
<% #books.each do |book| %>
<%= book.title %>
<%= book.author %>
<p>Comments:</p>
<% book.comments.each do |comment| %>
<%= comment.text %>
<% end %>
<% end %>
I have some suggestion for you.
You can write like this
class DashboardController < ApplicationController
def index
#books = current_user.books.includes(:comments)
end
end
It will get all of the comments you need, especially you also avoid n+1 query.
Or you can also write
class DashboardController < ApplicationController
def index
#books = current_user.books
#comments = current_user.comments.where('id = ?', #books.pluck(:id))
end
end
There are existing companies and orientations(landscape, portrait) and have to create app_accesses(STI type: iPhone, iPad, desktop) for the company.
The view is drop-down of app_accesses types and checkbox of orientations and the requirement is to save app_accesses for the company with the type selected and orientations checked
So for single company's single AppAccess type and multiple orientation_id's the join table should be saved
Models
class Company < ApplicationRecord
has_many :app_accesses
has_many :orientations, through: :app_accesses
accepts_nested_attributes_for :app_accesses
end
class Orientation < ApplicationRecord
has_many :app_accesses
has_many :companies, through: :app_accesses
end
class AppAccess < ApplicationRecord
belongs_to :company
belongs_to :orientation
accepts_nested_attributes_for :orientation
end
And Controller looks like
class CompaniesController < ApplicationController
before_action :find_company, only: [:show, :edit, :update, a_access_new, :a_access_create]
def new
#company = Company.new
end
def create
#company = Company.new(company_params)
#company.save
end
def a_access_new
#com_acc = Company.find(params[:id])
#com_acc.app_accesses.build.build_orientation
end
def a_access_create
//save attributes here
end
end
The view looks like
= form_for #com_acc, url: a_access_create_company_path(#com_acc), :method => :POST , local: true do |f|
= f.fields_for :app_accesses do |app|
.row
- devices = ['Iphone', 'Ipad', 'Desktop']
= app.label :type, 'Device Type:', class: "col-lg-3 control-label"
.col-lg-9
= app.collection_select :type, devices, :to_s, :to_s, class: 'form-control custom-checkbox'
= app.fields_for :orientation do |orient|
= orient.collection_check_boxes(:id, Orientation.all, :id, :name, include_hidden: false) do |b|
= b.check_box
= b.label
.row
= f.submit 'Save'
How would the strong parameters be? I am facing issues with the parameters and they are not being saved.
Also getting an error like accepts_nested_attributes_for to link to existing record, not create a new one while saving
I have to build a simple app that allows users to loan and borrow books. Simply put a User can create books, and they can pick another user to loan the book to.
I have three models User, Book and Loan:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :books
has_many :loans, through: :books
has_many :borrowings, class_name: "Loan"
validates :username, uniqueness: true
validates :username, presence: true
end
class Book < ActiveRecord::Base
belongs_to :user
has_many :loans
validates :title, :author, presence: true
end
class Loan < ActiveRecord::Base
belongs_to :user
belongs_to :book
validates :user, :book, :status, presence: true
end
The LoansController looks like this:
class LoansController < ApplicationController
before_action :find_book, only: [:new, :create]
def new
#users = User.all
#loan = Loan.new
authorize #loan
end
def create
#loan = Loan.new
#loan.book = #book
#loan.user = User.find(loan_params[:user_id])
#loan.status = "loaned"
authorize #loan
if #loan.save
redirect_to :root
else
render :new
end
end
private
def loan_params
params.require(:loan).permit(:user_id)
end
def find_book
#book = Book.find(params[:book_id])
end
end
My form looks like:
<%= simple_form_for([#book, #loan]) do |f| %>
<%= f.input :user_id, collection: #users.map { |user| [user.username, user.id] }, prompt: "Select a User" %>
<%= f.submit %>
<% end %>
If I submit the form without selecting a user, and keep the "Select a User" prompt option, the form is submitted and the app crash because it can't find a user with id=
I don't know why the user presence validation in the form does not work...
you will change your Create method
def create
#loan = Loan.new
#loan.book = #book
#loan.user = User.find_by_id(loan_params[:user_id])
#loan.status = "loaned"
authorize #loan
if #loan.save
redirect_to :root
else
render :new
end
end
I am trying to save the attributes of an assignment-model through a form for a person-model:
class Person < ActiveRecord::Base
has_one :assignment, dependent: :destroy
accepts_nested_attributes_for :assignment, allow_destroy: true
end
class Assignment < ActiveRecord::Base
belongs_to :person
belongs_to :project
end
class Project < ActiveRecord::Base
has_many :reverse_assignments, class_name: 'Assignment'
end
class PersonsController < ApplicationController
def new
#person = Person.new
end
def create
#person = Person.build(person_params)
#person.build_assignment(assignment_params) # Shouldn't this be obsolete?
redirect_to root_url
end
private
def person_params
params.require(:person).permit(:name, assignment_attributes: [:id, :project_id])
end
def assignment_params
params.require(:assignment).permit(:person_id, :project_id) # Only needed because of the "obsolete" line
end
end
class AssignmentsController < ApplicationController
end
This is the form (slim-html):
= form_for(#person) do |f|
= f.text_field :name
= fields_for :assignment do |r|
= r.collection_select :project_id, Project.order(:name), :id, :name
= f.submit 'Save'
Creating the assignment through the project-form works, but only by including a second line in the PersonsController's create action. However, shouldn't the first line suffice, because I already included the assignment_params in the person_params? I am asking, because I have issues updating the assignment through an edit-person-form which uses very similar code.
= form_for(#person) do |f|
= f.text_field :name
= f.fields_for :assignment do |r|
= r.collection_select :project_id, Project.order(:name), :id, :name
= f.submit 'Save'
Try adding the f.fields_for
You may also want to add this to your "new" action:
def new
#person = Person.new
#person.build_assignment
end
This builds the ActiveRecord object for assignment, which is then passed through the nested attributes to the other model :)
I am stuck with the friendships model. I can be friends with an user multiple times. So I need a condition to avoid add to friend link .
My users_controller :
class UsersController < ApplicationController
before_filter :authenticate_user!
def index
#users = User.all
end
def show
#user = User.find(params[:id])
#topics = #user.topics.paginate(page: params[:page])
#friendship = #user.friendships.build(:friend_id => params[:friend_id])
#friendships = #user.friendships.all
end
my show.html.erb:
<section>
<h1><%= #user.username %></h1>
<%= link_to "Arkadaşlarıma Ekle", friendships_path(:friend_id => #user), :method => :post,class: "btn btn-large btn-primary" %>
</section>
my friendships_controller :
class FriendshipsController < ApplicationController
before_filter :authenticate_user!
def create
#friendship = current_user.friendships.build(:friend_id => params[:friend_id])
if #friendship.save
flash[:notice] = "Arkadaşlara eklendi."
redirect_to root_url
else
flash[:error] = "Arkadaşlara Eklenemiyor."
redirect_to root_url
end
end
def destroy
#friendship = current_user.friendships.find(params[:id])
#friendship.destroy
flash[:notice] = "Arkadaşlarımdan kaldırıldı."
redirect_to current_user
end
end
so I guess , I tried add this method in users_controller but still no solution for it. Can you help me to fix it?
def friend?(other_user)
friendships.find_by_friend_id(other_user.id)
end
and In before link
<% unless friend?(#user) %>
%= link_to "Arkadaşlarıma Ekle", friendships_path(:friend_id => #user), :method => :post,class: "btn btn-large btn-primary" %>
<%end %>
My user model :
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username
# attr_accessible :title, :body
has_many :topics
has_many :posts
has_many :friendships
has_many :friends, :through => :friendships
has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
has_many :inverse_friends, :through => :inverse_friendships, :source => :user
end
my Friendship model :
class Friendship < ActiveRecord::Base
attr_accessible :friend_id, :user_id
belongs_to :user
belongs_to :friend, :class_name => "User"
validates :friend, :presence => true, :unless => :friend_is_self
def friend_is_self
user_id == friend_id ? false : true
end
end
I think it is best to do such validations on the model level. use validate_uniqueness_of in your model and test for validity in your controller.
I think the friend? method should be something similar as:
def friend?(other_user)
current_user.friendships.find_by_friend_id(other_user.id)
end
since I guess friendship should be a table with user_id and friend_id, what we want to check is if this user has othter_user as a friend or not.
Your friend? method is returning the friendship or nil, not true or false as you would expect with a ? method.
Try
def friend?(other_user)
# this assumes Friendship is a user, which probably isn't true
# but I don't have your models but this should give you the right idea
self.friendships.include other_user
end