Update status will show user name - ruby-on-rails

Previously in my app only the owner of a guideline could edit his own guideline, but I would like anyone to be able to edit a guideline and then when it has updated it will say 'Edited by .... on .... date'. Is this possible?
my update action in guidelines_controller.rb is
def update
#guideline = Guideline.find(params[:id])
if params[:guideline] && params[:guideline].has_key?(:user_id)
params[:guideline].delete(:user_id)
end
respond_to do |format|
if #guideline.update_attributes(params[:guideline])
format.html { redirect_to #guideline, notice: 'Guideline was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "show" }
format.json { render json: #guideline.errors, status: :unprocessable_entity }
end
end
end
and edit action in the same controller is
def edit
#guideline = Guideline.find(params[:id])
#specialties = Guideline.order(:specialty).uniq.pluck(:specialty)
end
User Model user.rb is
attr_accessible :content, :hospital, :title, :user_id, :guideline_id, :specialty
has_many :guidelines
has_many :favourite_guidelines
guidelines model is
belongs_to :user
has_many :favourite_guidelines

If you want to maintain the history of the edits, then you have to create another table (guideline_edits : guideline_id, user_id, edited_at) and you can show the last edited by at . If you also want to track the changes that went into each of the edits, you can actually use audited gem
If you do not want to maintain the history, you can add edited_by (current user), edited_at (Time.now()) fields to your guideline and update these columns on updating the guideline.
And ofcourse, in your authorization rules, you have to allow any logged-in user to edit any guideline.
Hope this helps

Related

How to make model associations between two models in Ruby. Or How to take data from one model and use it in another model?

So I create two models, one "Course" and one "Section" with scaffold and need Section to display Courses in a drop down menu that reflects any courses that were created in the course model and use it to create in section. I've been able to get the drop down menu displaying the courses created from "Course", but when I create the new section is displays the course as blank. Course has a Name, Department, Number, and Credit Hours. Section has Semester, Number, Course, and Room Number.
What I modified to make the drop down menu was ( in _form.html.erb of views of section )
<div class="field">
<%= form.label "Courses", class: 'courses'%>
<%= form.collection_select(:section, Course.all, :id, :name) %>
</div>
This gives an error of "Courses must exist"
Previously I had:
<div class="field">
<%= form.label "Courses", class: 'courses'%>
<%= form.collection_select(:course_ids, Course.all, :id, :name) %>
This did not give an error and allowed me to create a section, just without adding the selected course to the section database.
https://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_select
From reading it appears :name should be defined in the models portion of Course, but when I try it gives an error. I also realize I do not have it set to record Course to a specific section ID which is why it isn't saving it when a new section is created. My question is, what do I add or modify to make that work? Is using collection select the wrong thing to do?
EDIT to include sections_controller.rb
class SectionsController < ApplicationController
before_action :set_section, only: [:show, :edit, :update, :destroy]
# GET /sections
# GET /sections.json
def index
#sections = Section.all
end
# GET /sections/1
# GET /sections/1.json
def show
end
# GET /sections/new
def new
#section = Section.new
end
# GET /sections/1/edit
def edit
end
# POST /sections
# POST /sections.json
def create
#section = Section.new(section_params)
respond_to do |format|
if #section.save
format.html { redirect_to #section, notice: 'Section was successfully created.' }
format.json { render :show, status: :created, location: #section }
else
format.html { render :new }
format.json { render json: #section.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /sections/1
# PATCH/PUT /sections/1.json
def update
respond_to do |format|
if #section.update(section_params)
format.html { redirect_to #section, notice: 'Section was successfully updated.' }
format.json { render :show, status: :ok, location: #section }
else
format.html { render :edit }
format.json { render json: #section.errors, status: :unprocessable_entity }
end
end
end
# DELETE /sections/1
# DELETE /sections/1.json
def destroy
#section.destroy
respond_to do |format|
format.html { redirect_to sections_url, notice: 'Section was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_section
#section = Section.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def section_params
params.require(:section).permit(:semester, :number, :course, :room_number)
end
end
I believe I need to relate them somehow with the last part:
def section_params
params.require(:section).permit(:semester, :number, :course, :room_number)
EDIT:
(source: rubyisonrails.com)
http://rubyisonrails.com/pictures/part2.PNG">
First, you should change courses to course in the Section model. The association name for the belongs_to should always be singular
class Section < ApplicationRecord
belongs_to :course #singular name
end
Second, you should have course_id column instead of course in the sections table. You can generate a migration which will reflect these changes in the table
rails g migration modify_sections
The above command should generate a file like xxxxxxxmodify_sections.rb under db/migrate folder. Open the file and add
def change
add_column :sections, :course_id, :integer
remove_column :sections, :course, :integer
end
and do rake db:migrate
Now change the collection_select like the below
<%= form.collection_select(:course_id, Course.all, :id, :name) %>
And in the sections_controller#create, add
#section.course_id = params[:section][:course_id]
before the respond_to do |format|
Finally, change course to course_id in the section_params method.
def section_params
params.require(:section).permit(:semester, :number, :course_id, :room_number)
end
Note:
As you are very new to the technology, I recommend you to follow the Guides to learn.

Rails Associations: belongs_to has_many confusion

I've read through the following tutorial and found the curious line:
notice that the create function is written in such a way that there has be a #post before creating a #comment.
You can see the supporting controller code:
Class CommentsController < ApplicationController
----
def create
#post = Post.find(current_post)
#comment = #post.comments.create(post_params) ## 'Essential stuff'
respond_to do |format|
if #comment.save
format.html { redirect_to action: :index, notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
----
end
Indeed, "current_post" implies that the post was created BEFORE the comment.
But what if I want both to be created simultaneously? For example, suppose my USER has_many EMAILS, and each EMAIL belongs_to a USER. Then, when creating a new user, I may want to have an expandable form that allows the user to add one, two, three, or twenty emails while creating his account.
How could this be done?
Nested Attributes is the rails way of doing what you want to achieve.
Checkout http://railscasts.com/episodes/196-nested-model-form-part-1
You need to consider using nested form, have a look into this gem, very easy to implement. It will allow the user to add multiple emails as required.

How to properly associate a model with multiple models?

I've tried to implement many of the proposed solutions in the relevant questions, but haven't yet found an answer ideal for what I'm trying to achieve in my Rails 4 application.
Basically my app has three models. Users, Hooks (embeddable pop-up widgets) and Contacts. Users can create Hooks and Contacts within their interface. And any visitor can create a new contact by filling out the Contact create form placed within a Hook's view, and that contact is associated with the user who created that hook.
That works fine, however when a contact is created by filling out a Hook's form, there's no connection to the specific Hook they completed the form in.
The next set of features I would like to add to my app requires not only associating each contact with a user, but also with the specific Hook it was created from.
I've read a bit into polymorphic associations (model belongs to multiple models) and I understand that's probably the way to go. After a couple of failed attempts, I'm not sure how to implement it though.
How would I associate Contacts with Hooks, so users can know which hook a contact was created from?
Here is what I currently have in the Hooks controller and model...
def create
#hook = hook.new(hook_params)
#hook.user = current_user
#contact = Contact.new(contact_params)
respond_to do |format|
if #hook.save
format.html { redirect_to #hook, notice: 'Hook was successfully created.' }
format.json { render :show, status: :created, location: #hook }
format.js
else
format.html { render :new }
format.json { render json: #hook.errors, status: :unprocessable_entity }
format.js
end
end
end
class Hook < ActiveRecord::Base
belongs_to :user
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "https://s3.amazonaws.com/app/assets/leadmagnet.png"
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
end
And here is the contacts controller and model...
def create
#contact = Contact.new(contact_params)
#contact.user = current_user
respond_to do |format|
if #contact.save
if user_signed_in?
format.html { redirect_to #contact, notice: 'Contact was successfully created.' }
else
format.html { redirect_to #contact, notice: 'Contact was successfully created.' }
end
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
class Contact < ActiveRecord::Base
belongs_to :owner, :class_name => 'User'
belongs_to :user
validates :email, :presence => {:message => 'Email cannot be blank'}
end
First off, you should never ever ever create 2 unrelated models on the same controller action. It breaks conventions and will only lead to problems.
You do not need to directly associate Contacts to Users. You should associate Contacts to Hooks and then associate Contacts through Hooks
class User < ActiveRecord::Base
has_many :hooks
has_many :contacts, through: :hooks
end
class Hook < ActiveRecord::Base
belongs_to :user
has_many :contacts
accepts_nested_attributes_for :contacts
end
class Contact < ActiveRecord::Base
belongs_to :hook
end
Now on the create action of the ContactsController, you can first get the Hook either by URL param or passed via post body. You can first find the Hook and create the Contact on it via:
hook = Hook.find(hook_id)
#contact = hook.contacts.new(contacts_param)
If you want to create contacts when creating a new Hook, you need to add :contacts_attributes on the strong_params, then pass an array of contact attributes via the POST. Adding accepts_nested_attributes_for to the Hook model allows you to easily create Contacts while creating Hooks by simply entering:
#hook = Hook.new(hook_params)
If I understand correctly, you want to create both a Hook and a Contact, and associate both to current_user. In your code you create both, but you only associate #hook with the current_user, and only save it, while ignoring the #contact. Simply associate it and save it as well:
def create
#hook = hook.new(hook_params)
#hook.user = current_user
#contact = Contact.new(contact_params)
#contact.user = current_user
respond_to do |format|
if #hook.save && #contact.save
format.html { redirect_to #hook, notice: 'Hook was successfully created.' }
format.json { render :show, status: :created, location: #hook }
format.js
else
format.html { render :new }
format.json { render json: #hook.errors + #contact.errors, status: :unprocessable_entity }
format.js
end
end
end

Subform for parent object

So I've been holding off putting a question on here because I don't want to bother the community with stupid questions, but I'm going to ask for help now anyway.
I'm quite new to Ruby on Rails, and as you've probably read from the title, I'm having trouble with my subform. More specifically, with assigning the parent object to a client object. I'm building a system for my work in where employees can register repairs (mobile phones) and keep track of them. I'm building the client object with #repair = Repair.new, which works fine, but when I try to set the Client with #repair = Client.new, the :client_id on the repair stays null.
Here's my repair.rb: (some fields are in Dutch, please ignore that)
class Repair < ActiveRecord::Base
attr_accessible :imei, :klantnaam, :telefoon, :intake, :branch_id, :id, :client_id
attr_accessible :merk, :type, :batterij, :lader, :headset, :batterijklep, :carkit, :schade_toestel, :schade_scherm, :bon, :datum_bon, :klacht, :prijsindicatie
belongs_to :branch
belongs_to :client
accepts_nested_attributes_for :client
end
client.rb:
class Client < ActiveRecord::Base
attr_accessible :email, :firstname, :lastname, :number, :phone, :postalcode
has_many :repairs
end
repairs_controller.rb: (I've left the irrelevant methods out, I was getting tired of the 4 spaces :P)
class RepairsController < ApplicationController
# GET /repairs/new
# GET /repairs/new.json
def new
#repair = Repair.new
#repair.client = Client.new
if request.remote_ip == "xx.xx.xx.xx"
#repair.branch = Branch.where(:name => "Xxxxxxx").first
end
#repair.intake = Time.now
respond_to do |format|
format.html # new.html.erb
format.json { render json: #repair }
end
end
# POST /repairs
# POST /repairs.json
def create
#repair = Repair.new(params[:repair])
respond_to do |format|
if #repair.save
format.html { redirect_to #repair, notice: 'Repair was successfully created.' }
format.json { render json: #repair, status: :created, location: #repair }
else
format.html { render action: "new" }
format.json { render json: #repair.errors, status: :unprocessable_entity }
end
end
end
end
And this is the JSON I get from /repair/new.json:
{"batterij":null,"batterijklep":null,"bon":null,"branch_id":null,"carkit":null,"client_id":null,"created_at":null,"datum_bon":null,"headset":null,"id":null,"imei":null,"intake":"2013-02-01T23:29:10Z","klacht":null,"klantnaam":null,"lader":null,"merk":null,"pickup":null,"prijsindicatie":null,"schade_scherm":null,"schade_toestel":null,"telefoon":null,"updated_at":null}
By the way, the branch assignment works flawlessly... (It's null now because I'm not on the IP I specified in the new method)
Please help me out... :-(
Robin
Solved it!!
The code above all works flawlessly, the problem was a <% instead of <%= in my view, which made my subform not show up. Duhh.

Rails editing an Image attached to a model

I'm trying to set up a model (client) that contains some general attributes about a company but also has a company logo attached. I'm reluctant to use a plugin because I want to grasp this aspect of rails if possible.
I've created a clients model and an image model and I can create a new client (scaffold code) and upload an accompanying image ok (using has_one :image, and belongs_to :client).
I used the following code (taken straight from Agile Rails 3rd ed)
class Client < ActiveRecord::Base
has_one :image
def uploaded_image=(image_file)
self.image = Image.new
self.image.name = base_part_of(image_file.original_filename)
self.image.content_type = image_file.content_type
self.image.data = image_file.read
end
def base_part_of(filename)
File.basename(filename).gsub(/^\w_-/,'')
end
end
when editing the client object however, the new file is uploaded but the changes aren't reflected in the db. Do I need to explicitly call update-attributes on #client.image? At the moment my controller update method is as follows:
def update
#client = Client.find(params[:id])
respond_to do |format|
if #client.update_attributes(params[:client])
flash[:notice] = 'Client was successfully updated.'
format.html { redirect_to(#client) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #client.errors, :status => :unprocessable_entity }
end
end
end
Thanks in advance for any tips, apologies for the noob question
I would strongly recommend to use Paperclip instead. It just works.

Resources