I want to edit a 3 model on has_many. My question is about the controller and how can I access the information
I have the following model
Customer Book Book_Manager
id id id
first description customer_id
last book_id
email visible
password
The relationship his has follow
Customer
has_many book_managers
has_many books :through -> book_managers
Book
has_many book_managers
has_many customer :through -> book_managers
Book_managers
belongs_to :customer
belongs_to :book
When a customer wants to edit the content, i want to be the latest one to be shown if any exist. The query i have at the moment doesn't seem to handle an empty case and not sure how to do it.
#book = current_customer.books.order("created_at DESC").first
How should i declare it in a def edit of the customercontroller??
Update: I want to be able to see my data, unfoturnotly it doesn't seem to work here my
customer controller
def create
#customer = Customer.new(params[:customer])
#book = #customer.books.build(params[:book])
if #customer.save
cookies[:auth_token] = #customer.auth_token
redirect_to #customer, notice: "Thank you for signing up!"
else
render "new"
end
end
def edit
#customer = Customer.find(params[:id])
if current_customer.books.length > 0
#book = current_customer.books.order("created_at DESC").first
else
#Nor books were found, so create one that has the proper relationship to current_customer
#book = current_customer.books.build
end
end
I am rendering a partial from the book folder, should my create option be in the customer Controller or in bookControllers
Update: using customerController has my main create, when creating its say missing actions in books controller should i have more action in the book controller?
All you need to do is a simple check in the controller to see if any books exist. If one does not exists then create a new one.
#Check if the books array contains anything. There are several ways to do this
if current_customer.books.length > 0
#book = current_customer.books.order("created_at DESC").first
else
#Nor books were found, so create one that has the proper relationship to current_customer
#book = current_customer.books.build
end
Related
So i have 2 models Users and books. Books has user_id,name, User has name,adress. Both have views. I did create a link_to in user view to redirect to books view, but i want to redirect by id.
What i mean if i click in User1 link_to, i want to view only user1 books(books that have only user_id:1 if it is possible to see the most recent created at the beginning, so if i have created book.id=5 would get first and book.id=1 would be lastone).
User model:
Class User < ApplicationRecord
has_many :books
Book Model:
Class Book < ApplicationRecord
belongs_to :user
Controller book show:
def show
#book = Book.all
end
if you need anything else, just ask in comments and i will edit. Also sorry if im not explaining correctly.
In your books#index controller action
def index
#books = Book.all
#books = #books.where(user_id: params[:user_id]) if params[:user_id].present?
end
And in your users#show view
link_to "This user books", books_path(user_id: #user.id)
So if you will go to /books you will see all books
But if you click the link on user's page -- you will see only this user books
For me, the best soluction is leave the default methods and create a new one:
def show_user_books
#books = Book.where(user_id:params[:user_id]).order(created_at: :desc) if params[:user_id].present?
redirect_to books_path
end
I have this model, called products, that has an id, user_id and product_name.
I have a simple form_for to pass to my product_controller the product_name param. In this same controller, I have access to the current_user, which I have to pass in order to create a new Product.
The problem is that the user_id always has to be the current user logged in, so I can't allow the user to send me this param in my form_for, thus I can't permit it as well.
What I'm doing right now is to create a new hash with the user_id param, and merge the params that comes from the form.
products_controller.rb:
def create
product_user_id_param = { "user_id": current_user.id.to_s }
#product = Product.new(product_user_id_param.merge(params[:product_name]))
...
end
Is there a more convenient or Rails way to do this?
You can create you product with you current_user reference, this is the more convenient way in my opinion:
current_user.produtcs.create(name: params[:product_name])
But, to above code works, you have to construct you relations correctly, like the following:
class User < ActiveRecord::Base
has_many :products
end
class Product < ActiveRecord::Base
belogs_to :user
end
Now, you can do it!
You can read more about it, in https://guides.rubyonrails.org/v3.2/association_basics.html, the docs recommeds this way!
Solution #1
Product has user_id which means product belongs_to :user and user has_many :products
Hence it can be written as
current_user.products.new(product_name: params[:product_name])
Solution#2
Set current_user explicitly
#product = Product.new(product_name: params[:product_name])
#product.user_id = current_user.id
##product.user = current_user
#product.save
When a user creates a new booking record, part of the data entered is an email address. This email address is used to create a new guest record at the same time if they don't already exist. The booking should have the guest id as part of the record.
In my models I have defined the relationships so:
accommodations has_many bookings
guests has_many bookings
bookings belongs_to accommodations
bookings belongs_to guests
This is what I have so far in the create action of my BookingsController:
...
def create
accommodation = current_user.accommodation
#booking = accommodation.bookings.build(post_params)
#guest = accommodation.guests.build(params[:email])
if #booking.save
flash[:success] = 'The booking has been added successfully.'
redirect_to :controller => 'bookings', :action => 'index'
else
render 'new'
end
end
...
My questions are:
Should I use 'build' twice as I want the new booking to have the guest id?
How can I check if guest exists already using email?
Is it safe/secure to use params[:email] when building the guest?
If you're not using #guest in the view, there's no need for it to be an instance variable. So:
accommodation = current_user.accommodation
guest = Guest.find_or_create_by(:email => params[:email])
#booking = accommodation.bookings.new(post_params.merge(:guest_id => guest.id))
You don't need to use build in your #create method because its main use is to maintain association ties with objects that still don't have a primary key. But since you're persisting your stuff in here, we can go with good old new from Ruby.
I have a form to create posts. This form also has tags on the post and it is owned by a user. The form is using a virtual attribute :tag_ids.
I would like to do something like this, where you find_or_create_by_name_and_user_id and then just pass the current_user.id.
def tag_ids=(tags_string)
self.taggings.destroy_all
tag_names = tags_string.split(",").collect{|s| s.strip.downcase}.uniq
tag_names.each do |tag_name|
tag = Tag.find_or_create_by_name_and_user_id(tag_name, current_user.id)
tagging = self.taggings.new
tagging.tag_id = tag.id
end
end
From what I read this isn't how it should work. The current user should be called in the PostsContoller create method.
def create
#post = Post.new(params[:post])
#post.user = current_user
respond_to do |format|
if params[:commit]
#post.save
...
end
This is where I'm stuck. If the params are passing all of the attributes, how can I inject the current_user id into tag model which has a :name and :user_id attribute?
I also read that this should work because of my associations.
User - has_many posts; has_many tags
Post - belongs_to user; has_many taggings; has_many tags through taggings
Tag - has many taggings; has_many posts through taggings; belongs_to user
Tagging - belongs_to post; belongs_to tag
You can't get current_user in model ,you have to pass explicitly,there are may be couple of hack to do this,But simple way is,user is already stored in post so self.user.id is useful
If above method is in post model,post user is tagging user.
Tag.find_or_create_by_name_and_user_id(tag_name, self.user.id)
Every company is supposed to have one CompanyContact. My Company form has fields for company contacts. When I update the Company and add a new company contact, it works fine, because in the show page for company, it does show the new company contact. But when I click the Edit link that takes me to the Edit page (note: I don't even click the update button yet), in the Edit Company form where the companycontact is supposed to be is blank. So i check the logs and the companycontact was deleted.
DELETE FROM "company_contacts" WHERE "company_contacts"."id" = ? [["id", 4]]
I'm confused because I haven't called any delete action.
----------------------------------------
company.rb
has_one :company_contact, :dependent => :destroy
accepts_nested_attributes_for :company_contact
----------------------------------------
company_contact.rb
belongs_to :company
----------------------------------------
companies_controller.rb
def new
#company = Company.new
company_contact = #company.build_company_contact
respond_to do |format|
format.html # new.html.erb
format.json { render json: #company }
end
end
def edit
#company = Company.find(params[:id])
company_contact = #company.build_company_contact
end
In your edit action you're building a company contact for your company, but your company has only one company contact. Check for existence before building a new one:
company_contact = #company.company_contact || #company.build_company_contact
I found this in the ActiveRecord source, which confirms the suspicion I commented on above (comments in the code below are mine):
class HasOneAssociation < SingularAssociation #:nodoc:
def replace(record, save = true)
raise_on_type_mismatch(record) if record
load_target
reflection.klass.transaction do
# !!!
# This is where your record is getting deleted
# !!!
if target && target != record
remove_target!(options[:dependent]) unless target.destroyed?
end
if record
set_owner_attributes(record)
set_inverse_instance(record)
if owner.persisted? && save && !record.save
nullify_owner_attributes(record)
set_owner_attributes(target) if target
raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
end
end
end
self.target = record
end
...
This replace method appears to be called whenever record.build_association is used.
Your edit action shouldn't build the associated record if one already exists.