Rails 4 : find or create method - ruby-on-rails

I have an association between experience and company where company has_many :experiences and experience belongs_to :company, Now I want to design this: if a user enters a company name that already exist in the company model it will assign to it but if the user put a company name that doesn't already exist in company model - the company must persist but not be created as a new record (I don't want to use find_or_create method and the find_by doesn't seem working for this situation)
Edit
this is my Company controller
def allcompanies
#companies = Company.paginate(page: params[:page], per_page: 10).order("created_at DESC")
end
def show
#company = Company.find_by_slug(params[:id])
if #company
render action: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
end
def index
#companies = Company.limit(19).order("id DESC")
end
def new
#company = Company.new
end
def edit
end
def create
#company = Company.new(company_params)
respond_to do |format|
if #company.save
flash[:notice] = "Entreprise '#{#company.name}' Crée!"
format.html { redirect_to #company}
else
format.html { render action: 'new' }
end
end
end
def update
respond_to do |format|
if #company.update(company_params)
flash[:notice] = "Entreprise '#{#company.name}' à été mis à jour"
format.html { redirect_to #company }
else
format.html { render action: 'edit' }
end
end
end
def destroy
#company.destroy
respond_to do |format|
format.html { redirect_to companies_url }
end
end
private
def set_company
#company = Company.find_by_slug(params[:id])
end
def company_params
params.require(:company).permit(:name, :company_description, :country, :city, :company_status, :company_size, :company_website, :sector_ids, :job_id, :companylogo)
end
and this is my experience model that actually create a new record for each company
belongs_to :profile
belongs_to :company
validates :company_name, presence: true
def company_name
company.try(:name)
end
def company_name=(name)
self.company = Company.find_or_initialize_by(name: name)
end

OK, so you want some companies to be visible and some not.
Then, you can create a corresponding boolean field, like public_visible and set it to false for companies you don't know(ie created by application users).
In your controller do something like this:
#company = Company.find_by_name(params[:company][:name])
if #company.blank?
#company = Company.create(params[:company].merge({ public_visible: false }))
end
#company.experiences.create(...)
it is just an example, since I don't know your real conditions on companies creation, so you need to adjust it according to your needs.

Related

building an order from a cart

i've been having issues trying to build a Cart + Cart/OrderItem + Order combination simple enough yet effective. I've looked around online but i couldn't find anything that fit, so i tried something but .. i'm a bit blocked atm, i don't see how to continue with this. The problem is that i don't know how to get the items in the order and start the cart from scratch (btw it's kind of messy). Also a nice simple tutorial on this would be appreciated as well. Do note i already went through agile web's book example, but for some reason i didn't follow it, it didn't seem to be what i was looking for.
controllers - cart + order
class CartsController < ApplicationController before_filter :initialize_cart
def add
#cart.add_item params[:id]
session["cart"] = #cart.serialize
product = Product.find(params[:id])
redirect_to :back, notice: "Added #{product.name} to cart." end
def show end
def checkout
#order = Order.new user: User.new end end
class OrdersController < ApplicationController
def index
#orders = Order.order('created_at desc').page(params[:page])
end
def show
end
def new
#order = Order.new
end
def create
#order = Order.new(order_params)
respond_to do |format|
if #order.save
format.html { redirect_to root_path, notice:
'Thank you for your order' }
format.json { render action: 'show', status: :created,
location: #order }
else
format.html { render action: 'new' }
format.json { render json: #order.errors,
status: :unprocessable_entity }
end
end
end
private
def set_order
#order = Order.find(params[:id])
end
def order_params
params.require(:order).permit(:pay_type, :user_id)
end
end
now the models
class Order < ActiveRecord::Base
belongs_to :user
PAYMENT_TYPES = [ "Check", "Credit card", "Purchase order" ]
validates :pay_type, inclusion: PAYMENT_TYPES
end
class CartItem
attr_reader :product_id, :quantity
def initialize product_id, quantity = 1
#product_id = product_id
#quantity = quantity
end
def product
Product.find product_id
end
def total_price
product.price * quantity
end
end
class Cart
attr_reader :items
def self.build_from_hash hash
items = if hash["cart"] then
hash["cart"]["items"].map do |item_data|
CartItem.new item_data["product_id"], item_data["quantity"]
end
else
[]
end
new items
end
def initialize items = []
#items = items
end
def add_item product_id
item = #items.find { |item| item.product_id == product_id }
if item
item+=1
else
#items << CartItem.new(product_id)
end
end
def empty?
#items.empty?
end
def count
#items.length
end
def serialize
items = #items.map do |item|
{
"product_id" => item.product_id,
"quantity" => item.quantity
}
end
{
"items" => items
}
end
def total_price
#items.inject(0) { |sum, item| sum + item.total_price }
end
end
Thank you.

Rails actionmailer sending emails for commentable model

I'm trying to send emails through my actionmailer to the commentable owners' email after another user writes them a comment but I keep getting an error. Can someone help me out with this? Thanks in advance.
comment_mailer.rb
def email_notification(member, comment)
#member = commentable.member
#sender = comment.member
mail to: commentable.member.email, subject: "#{comment.member.full_name} (#{comment.member.user_name}) has left you a comment"
end
comment.rb
belongs_to :member
belongs_to :commentable, polymorphic: true
attr_accessible :content
after_create :send_email
def send_email
CommentMailer.email_notification(member, comment).deliver
end
error
undefined local variable or method `comment' for #<Comment:0x51c2ad8>
app/models/comment.rb:18:in `send_email'
app/controllers/comments_controller.rb:20:in `block in create'
app/controllers/comments_controller.rb:19:in `create'
comments_controller
before_filter :authenticate_member!
before_filter :load_commentable
before_filter :find_member
def index
redirect_to root_path
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(params[:comment])
#comments = #commentable.comments.order('created_at desc').page(params[:page]).per_page(15)
#comment.member = current_member
respond_to do |format|
if #comment.save
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to :back }
format.json
format.js
end
end
end
def destroy
#comment = Comment.find(params[:id])
respond_to do |format|
if #comment.member == current_member || #commentable.member == current_member
#comment.destroy
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to :back, alert: 'You can\'t delete this comment.' }
format.json
format.js
end
end
end
private
def load_commentable
klass = [Status, Medium, Project, Event, Listing].detect { |c| params["#{c.name.underscore}_id"] }
#commentable = klass.find(params["#{klass.name.underscore}_id"])
end
def find_member
#member = Member.find_by_user_name(params[:user_name])
end
You error is in the send_email method. There is no local variable called comment. You are already inside an instance of comment, the instance you want to send an email about. So you want to use the keyword self instead.
Change this:
def send_email
CommentMailer.email_notification(member, comment).deliver
end
To this:
def send_email
CommentMailer.email_notification(member, self).deliver
end
self refers to the current instance of comment, which you want to use for your mailer.

How can I prevent "not-yet-approved" Admins from accessing Admin functions in my web app?

So that multiple people can be an administrator to a business page, we've created a model called administration where people can apply to be an admin of a business and thus the status of "0" is "pending" and "1" is accepted.
How can I prevent users from editing a page where their status for i is still "0" (pending).
class Administration < ActiveRecord::Base
attr_accessible :business_id, :user_id, :status
belongs_to :user
belongs_to :business
scope :pending, where('status = ?',0).order("updated_at desc")
def self.new_by_user_business( user, business)
admin = self.new
admin.business_id = business.id
admin.user_id = user.id
admin.status = 0
admin.save!
end
end
Here is the current "edit page"
<h1>Editing business</h1>
<%= render 'form1' %>
Here is the business controller.
class BusinessesController < ApplicationController
respond_to :html, :xml, :json
before_filter :authenticate_user!, except: [:index, :show]
def index
#businesses = Business.all
respond_with(#businesses)
end
def show
#business = Business.find(params[:id])
if request.path != business_path(#business)
redirect_to #business, status: :moved_permanently
end
end
def new
#business = Business.new
3.times { #business.assets.build }
respond_with(#business)
end
def edit
#business = get_business(params[:id])
#avatar = #business.assets.count
#avatar = 3-#avatar
#avatar.times {#business.assets.build}
end
def create
#business = Business.new(params[:business])
if #business.save
redirect_to #business, notice: 'Business was successfully created.'
else
3.times { #business.assets.build }
render 'new'
end
end
def update
#business = get_business(params[:id])
if #business.update_attributes(params[:business])
flash[:notice] = "Successfully updated Business."
end
#avatar = #business.assets.count
#avatar = 3-#avatar
#avatar.times {#business.assets.build}
respond_with(#business)
end
def destroy
#business = get_business(params[:id])
#business.destroy
respond_with(#business)
end
def my_business
#business = Business.all
end
def business_tickets
#user = current_user
#business = get_business(params[:id])
#tickets = #business.tickets
#business_inbox = TicketReply.where(:email => #business.callred_email)
end
def your_business
#user = current_user
#business = get_business(params[:id])
if #business.users.map(&:id).include? current_user.id
redirect_to my_business_businesses_path, notice: 'You are already an administator of this business.'
else
#admin = Administration.new_by_user_business( #user, #business)
BusinessMailer.delay(queue: "is_your_business", priority: 20, run_at: 5.minutes.from_now).is_your_business(#user,#business)
redirect_to #business, notice: 'Thank you for claiming your business, and we will be in touch with you shortly.'
end
end
def view_message
# #business = Business.find(params[:business_id])
#ticket = Ticket.find(params[:id])
#reply = #ticket.ticket_replies
end
private
def get_business(business_id)
#business = Business.find(business_id)
end
end
You could add a before_filter to check the status. You will have to change some of the logic but this is the idea
class BusinessesController < ApplicationController
before_filter :restrict_access, :only => [:edit, :update]
private
def restrict_access
#business = get_business(params[:id])
redirect to root_path, :notice => "Not Authorized" unless current_user.status == 1
end
end

ActiveRecord::RecordNotSaved - Forcing nested redirect

Morning All,
After spending most of the night figuring out how to put a limit on my model creation I finally got somewhere. The nested statement is now presenting me with not saved which is great news.
However I cannot seem to get the redirect or flash[:base] to work. Here is the code below:
class SnippetsController < ApplicationController
before_filter :find_book
def create
if #snippet = #book.snippets.create!(params[:snippet])
redirect_to #book
else
flash[:base]
#render
end
end
def approve
##snippet = #book.snippet.find(params[:id])
if #snippet.update_attribute(:approved, true)
redirect_to users_path
else
render root_path
end
end
def edit
#snippet = #book.snippets.find(params[:id])
end
def update
#snippet = #book.snippets.find(params[:id])
respond_to do |format|
if #snippet.update_attributes(params[:snippet])
format.html { redirect_to #book, notice: 'Comment was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
private
def find_book
#book = Book.find(params[:book_id])
end
end
Models parent (book)
class Book < ActiveRecord::Base
has_many :snippets
attr_accessible :title, :book_id, :size
def snippets_limit_reached?
if size == 0
self.snippets.count >= 2
elsif size == 1
self.snippets.count >= 3
elsif size == 2
self.snippets.count >= 4
else
return false
end
end
end
Child (Snippet)
class Snippet < ActiveRecord::Base
before_create :check_limit
belongs_to :book
attr_accessible :content, :book_id
validates :book_id, presence: true
def check_limit
if book.snippets_limit_reached?
errors.add :base, 'Snippet limit reached.'
return false
end
return true
end
end
Let me know if you need anything else, just fyi when it's running I cannot get past the nested create!
if #snippet = #book.snippets.create!(params[:snippet])
Bang methods (create!, save!) throw errors when unsuccessful, instead of returning, what evaluates to false.
Removing the bang should fix this problem.

Updating attributes through a different object

I am having a ridiculously hard time trying to figure out how to do this. I have been at it literally all day.
I have an Account class and a Transaction class.
Accounts are created with a balance and I want the Transaction amount, depending on its type, to either add or subtract from the balance.
I want to be able to update the Account balance every time a transaction is created. This is for a personal finance application. As of now when I create a new transaction, nothing happens to the account balance.
accounts_controller.rb
class AccountsController < ApplicationController
def index
#accounts = Account.all
end
def show
#account = Account.find(params[:id])
end
def new
#account = Account.new
end
def edit
#account = Account.find(params[:id])
end
def create
#account = Account.new(params[:account])
respond_to do |format|
if #account.save
format.html { redirect_to #account, notice: 'Account was successfully created.' }
format.json { render json: #account, status: :created, location: #account }
else
format.html { render action: "new" }
format.json { render json: #account.errors, status: :unprocessable_entity }
end
end
end
def update
#account = Account.find(params[:id])
respond_to do |format|
if #account.update_attributes(params[:account])
format.html { redirect_to #account, notice: 'Account was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #account.errors, status: :unprocessable_entity }
end
end
end
# DELETE /accounts/1
# DELETE /accounts/1.json
def destroy
#account = Account.find(params[:id])
#account.destroy
respond_to do |format|
format.html { redirect_to accounts_url }
format.json { head :no_content }
end
end
def update_balance
#a = Account.find(params[:id])
#a.transactions.each do |t|
#update_balance = t.t_type + #a.balance
#a.update_attributes(:balance => #update_balance)
end
end
end
transactions_controller.rb
class TransactionsController < ApplicationController
def create
#account = Account.find(params[:account_id])
#transaction = #account.transactions.create(params[:transaction])
redirect_to account_path(#account)
end
end
transaction.rb
class Transaction < ActiveRecord::Base
belongs_to :account
attr_accessible :amount, :category, :t_type
end
account.rb
class Account < ActiveRecord::Base
attr_accessible :balance, :name
has_many :transactions
end
If anyone has any idea what I'm doing wrong or can point me in the direction of a good thorough explanation, that would be great. I am so lost at this point.
Try this.
class Account < ActiveRecord::Base
attr_accessible :balance, :name
has_many :transactions
def update_with_transaction(transaction)
return unless self.transactions.include? transaction
if transaction.t_type.eql? SOME_TYPE
self.balance += transaction.ammount
else
self.balance -= transaction.ammount
end
save
end
end
class TransactionsController < ApplicationController
def create
account = Account.find(params[:account_id])
#transaction = account.transactions.create(params[:transaction])
account.update_with_transaction(#transaction)
redirect_to account_path(account)
end
end
It doesn’t update because you haven’t told it to. Create an after_create callback to do so:
class Transaction < ActiveRecord::Base
# ...
after_create :update_account_balance
private
def update_account_balance
account.balance += amount
account.save
end
end
Adjust as needed. Note that this won’t handle updates to a transaction’s amount, which is left as an exercise for the reader.

Resources