I have the following model:
class Action < ActiveRecord::Base
# model code stuff
end
In the controller, I can do something like that:
class ActionsController < ApplicationController
# super simple update
def update
#action = Action.find(params[:id])
#action.update_attributes(params[:action])
end
end
Is it possible to make my Action model to be represented by 'something_action' in params array without renaming the model itself? I.e. so I can retrieve it like that:
#action.update_attributes(params[:something_action])
Any help would be appreciated?
In your form_for use :as => :some_other_params_name
form_for(#action, :as => :different
If you are using form_for, you can change it to
form_for :something_action, #action do |f|
so it uses :something_action as the name of the params
Related
Trying to figure our how to set up associations in form.
I have 3 models:
class Request < ActiveRecord::Base
has many :answers
has many :users, through: :answers
end
class Answer < ActiveRecord::Base
belongs to :user
belongs to :request
end
class User < ActiveRecord::Base
has many :answers
has many :requests, through: :answers
end
I am trying to figure out: how to have a User link to Answer#new from Request#Show, and then create an Answer record passing in the Request#Show request_id from the previous page - creating an association between the User's Answer and the Request he was viewing.
My method of doing this now is: I flash the request_id value on Request#Show, and then when a User links to Answer#new, it passes the flashed value into a hidden form tag on Answer#new. This does not seem like the best way to do this.
Any thoughts?
Kudos for the creative approach using flash, however your right there is an easy way. You can pass parameters much between controllers just like passing parameters between methods using the route names.
I didn't quite follow what it was you were trying to achieve in this case but it looks like this blog entry here should get you started..
https://agilewarrior.wordpress.com/2013/08/31/how-to-pass-parameters-as-part-of-the-url-in-rails/
Good luck!
User link to Answer#new from Request#Show
This can be achieved with either sessions or nested resources (or both!). Let me explain:
I would definitely add a nested resource to your requests routes:
#config/routes.rb
resources :requests do
resources :answers, only: [:new, :create] #-> url.com/requests/:request_id/answers [POST]
end
This gives you the ability to call a "nested" route (IE one which sends data to a child controller, and requires "parent" data to be appended to the request).
In your case, you want to create an answer for a request. The most efficient way is to use a routing structure as above; this will allow you to use the following controller method:
#app/controllers/answers_controller.rb
class AnswersController < ApplicationController
def new
#request = Request.find params[:request_id]
#answer = #request.answers.new
end
def create
#request = Request.find params[:request_id]
#answer = #request.answers.new answer_params
#answer.save
end
private
def answer_params
params.require(:answer).permit(:title, :body)
end
end
The above gives you the ability to create an answer by passing the request_id to the nested route. You must note the corresponding route will require a POST method in order to work.
You don't need the new method. If you wanted it, it can easily be handled with the above structure.
Passing the user is a little more tricky.
You can either use the routes, or set a session.
I would personally set a session (it's cleaner):
#app/controllers/requests_controller.rb
class RequestsController < ApplicationController
def show
session[:user_id] = #user.id #-> I don't know how you populate #user
end
end
This will give you the ability to access this session here:
#app/controllers/answers_controller.rb
class AnswersController < ApplicationController
def new
user = User.find session[:user_id]
end
end
#app/views/requests/show.html.erb
<%= link_to "New Answer", request_new_answer_path(request) %>
--
If you're using Devise, the user object should be available in the current_user object (which means you don't have to set session[:user_id]):
#app/controllers/answers_controller.rb
class AnswersController < ApplicationController
def new
## current_user available here if using devise
end
end
To assign a #user to the new answer record, just do this in answers#create:
#app/controllers/answers_controller.rb
class AnswersController < ApplicationController
...
def create
#request = Request.find params[:request_id]
#answer = #request.answers.new answer_params
#answer.user = current_user
#answer.save
end
end
Something like this worked for me:
I have two models (Formula and FormulaMaterial)
Formula has_many FormulaMaterials, which belongs to Formula
My Formula controller sets #formula like so:
#formula = Formula.find(params[:id])
I list my Formula Materials in my Formula show.html.erb by declaring it in my Formula controller like so:
#formula_materials = FormulaMaterial.where(:formula_id => #formula)
When I want to add a new FormulaMaterial to my Formula, the "New Formula Material" button in my show.html.erb file looks like this:
<%= link_to 'Add Material To Formula', new_formula_material_path(:formula_id => #formula), class: "btn btn-success" %>
In the "new_..._path" I set the associated id to the #formula variable. When it passes through to the new.html.erb for my FormulaMaterial, my URL looks like so:
http://localhost:3000/formula_materials/new?formula_id=2
In my FormulaMaterial new.html.erb file, I created a hidden_field that sets the value of the association by using "params" to access the formula_id in the URL like so:
params[:formula_id] %>
I am not sure if this is the best way to do this, but this way has allowed me to pass through the view id from the previous page as a hidden, associated and set field in the form every time.
Hope this helps!
I have a controller named 'companies' and rather than the urls for each company being denoted with an :id I'd like to have the url use their :name such as: url/company/microsoft instead of url/company/3.
In my controller I assumed I would have
def show
#company = Company.find(params[:name])
end
Since there won't be any other parameter in the url I was hoping rails would understand that :name referenced the :name column in my Company model. I assume the magic here would be in the route but am stuck at this point.
Good answer with Rails 4.0+ :
resources :companies, param: :name
optionally you can use only: or except: list to specify routes
and if you want to construct a URL, you can override ActiveRecord::Base#to_param of a related model:
class Video < ApplicationRecord
def to_param
identifier
end
# or
alias_method :to_param, :identifier
end
video = Video.find_by(identifier: "Roman-Holiday")
edit_videos_path(video) # => "/videos/Roman-Holiday"
params
The bottom line is you're looking at the wrong solution - the params hash keys are rather irrelevant, you need to be able to use the data contained inside them more effectively.
Your routes will be constructed as:
#config/routes.rb
resources :controller #-> domain.com/controller/:id
This means if you request this route: domain.com/controller/your_resource, the params[:id] hash value will be your_resource (doesn't matter if it's called params[:name] or params[:id])
--
friendly_id
The reason you have several answers recommending friendly_id is because this overrides the find method of ActiveRecord, allowing you to use a slug in your query:
#app/models/model.rb
Class Model < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: [:slugged, :finders]
end
This allows you to do this:
#app/controllers/your_controller.rb
def show
#model = Model.find params[:id] #-> this can be the "name" of your record, or "id"
end
Honestly, I would just overwrite the to_param in the Model. This will allow company_path helpers to work correctly.
Note: I would create a separate slug column for complex name, but that's just me. This is the simple case.
class Company < ActiveRecord::Base
def to_param
name
end
end
Then change my routes param for readability.
# The param option may only be in Rails 4+,
# if so just use params[:id] in the controller
resources :companies, param: :name
Finally in my Controller I need to look it up the right way.
class CompaniesController < ApplicationController
def show
# Rails 4.0+
#company = Company.find_by(name: params[:name])
# Rails < 4.0
#company = Company.find_by_name(params[:name])
end
end
I recommend using the friendly_id for this purpose.
Please be noted that there are differences between friendly_id 4 and 5. In friendly_id 4, you can use like this
#company = Company.find(params[:id])
However, you won't be able to do that in friendly_id 5, you have to use:
#company = Company.friendly.find(params[:id])
In case that you don't want to use the params[:id] but params[:name], you have to override the route in routes.rb. For example
get '/companies/:name', to: "companies#show"
Hope these info would be helpful to you
There's actually no magic to implement this, you have to either build it yourself by correctly implementing to_param at your model (not recommended) or using one of the gems available for this like:
friendly_id
has_permalink
I use friendly_id and it does the job nicely.
Model.find(primary_key)
The default parameter here is primary_key id.
If you want to use other columns, you should use Model.find_by_xxx
so here it could be
def show
#company = Company.find_by_name(params[:name])
end
The :id parameter is whatever comes after the slash when the URL is requested, so a name attribute needs to be extracted from this by checking the :id parameter for non-numerical values with regular expressions and the match? method in the controller. If a non-numerical value is present, the instance can be assigned by the name attribute using the find_by_name() method that rails generated for the model (assuming that the model has an attribute called name)
That's how I figured out how to do it in my app with my Users resource. My users have a username attribute, and all I had to do was modify the UsersController to define my #user variable differently depending on the :id parameter:
private
# allow routing by name in addition to id
def get_user
if params[:id].match?(/\A\d+\Z/)
# if passed a number, use :id
#user = User.find(params[:id])
else
# if passed a name, use :username
#user = User.find_by_username(params[:id])
end
end
This gives me the option to use either id or username when I create a link to a particular user, or type it into the browser's address bar.
Then the only other (optional) thing to do is to change all the links in the views so that they point to the URL with the name instead of the URL with the id.
For example, within the link_to() method call in my navigation bar I changed
... user_path(current_user) ...
to
... user_path(current_user.username) ...
In your example, you might have a company view with the following link:
<%= link_to #company.name, company_path(#company.name) %>
Which, if the current company is Microsoft, would display "Microsoft" and link to "companies/Microsoft", even though the URL "companies/1" would still be valid and display the same thing as "companies/Microsoft"
Suppose I have this association:
class User < ActiveRecord :: Base
has_one :car
end
class Car < ActiveRecord :: Base
belongs_to :user
end
routes:
resources :users do
resources :cars
end
Then what would be the code, in the 'new' action method in CarsController
class CarsController < ApplicationController
def new
#??? what's necessary to be put here,
# if I have request 'localhost:3000/users/1/cars/new'
end
...
end
Will Rails figure out everything automatically so I don't have to write any code in the 'new' method? Also, since the 'new' action will generate a 'form_for(#car)' form helper, how can I create this car object
Is this right?
class CarsController < ApplicationController
def new
#user = User.find(params[:user_id])
#car = #user.build_car({})
end
end
That looks just fine. Rails will not do any of this automatically. There are gems out there that can automate some of that if you like, but the jury is out on whether they're actually worth your time.
If you have no params to pass to the car, you can just run #user.build_car with no arguments, by the way. You'll also need to specifically say in the form_for helper that you're nesting the car under the user: form_for [#user, #car] Otherwise the form's destination will be /cars instead of /user/1/cars.
You're pretty close, Baboon. I would actually do:
class UsersController < ApplicationController
def new
#user = User.new
#car = #user.cars.build
end
end
But if you don't want to create the Car at the same time as the user, try:
class CarsController < ApplicationController
def new
#user = User.find(params[:user_id])
#car = #user.cars.build
end
end
I found the nested_form railscast extremely helpful when doing this sort of thing. In fact, I think you'll probably get a lot out of it (and using the nested_form gem).
railscasts_196-nested-model-form-part-1
I want to capture an entire posts params, store it in the DB in one field (text), and then later get at each individual param? Possible? Any example you can show? thanks
You can serialize the entire params hash (or any other object)
class SomeModel < ActiveRecord::Base
serialize :params
…
end
class SomeModelsController < Applicationcontroller
def some_action
SomeModel.create(:params => params)
end
end
All you need is something like the following. I didn't include all of the Sendgrid params since there are so many and you will know what I mean with a few:
class SendgridMessage < ActiveRecord::Base
serialize :attachments
...
end
class SendgridMessagesController < ApplicationController
def create
SendgridMessage.create(:to => params[:to], :from => params[:from], :attachments => params[:attachments])
end
end
Sendgrid will send a POST to /sendgrid_messages with the params, and your object will be created with all of the correct fields (you will need to add some to the example) and serialized attachments like you are looking for.
perhaps
request.raw_post
is what you're looking for?
http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-raw_post
In my Ruby on Rails app, I've got:
class AdminController < ApplicationController
def create
if request.post? and params[:role_data]
parse_role_data(params[:role_data])
end
end
end
and also
module AdminHelper
def parse_role_data(roledata)
...
end
end
Yet I get an error saying parse_role_data is not defined. What am I doing wrong?
Helpers are mostly used for complex output-related tasks, like making a HTML table for calendar out of a list of dates. Anything related to the business rules like parsing a file should go in the associated model, a possible example below:
class Admin < ActiveRecord::Base
def self.parse_role_data(roledata)
...
end
end
#Call in your controller like this
Admin.parse_role_data(roledata)
Also look into using (RESTful routes or the :conditions option)[http://api.rubyonrails.org/classes/ActionController/Routing.html] when making routes, instead of checking for request.post? in your controller.
Shouldn't you be accessing the parse_role_data through the AdminHelper?
Update 1: check this
http://www.johnyerhot.com/2008/01/10/rails-using-helpers-in-you-controller/
From the looks of if you're trying to create a UI for adding roles to users. I'm going to assume you have a UsersController already, so I would suggest adding a Role model and a RolesController. In your routes.rb you'd do something like:
map.resources :users do |u|
u.resources :roles
end
This will allow you to have a route like:
/users/3/roles
In your RolesController you'd do something like:
def create
#user = User.find_by_username(params[:user_id])
#role = #user.roles.build(params[:role])
if #role.valid?
#role.save!
redirect_to #user
else
render :action => 'new'
end
end
This will take the role params data from the form displayed in the new action and create a new role model for this user. Hopefully this is a good starting point for you.