Rails 3: where query issue - ruby-on-rails

I am learning about 'where' in Rails 3 and I am wondering why my code is giving me a NoMethod Error.
def create
#get form values from 'new' page
#post = Post.new(params[:post])
#search for the inventory item with the sku code the user typed in the form
#item = Inventory.where(:sku_code => #post.sku_code)
#set post variable to a variable from the row with the sku code
#post.detail = #item.detail
#post.save
end
By searching the SKU, I want to retrieve the other variables in the same id and set them to my #post variable. Anyone able to give me a hand?

Assuming that SKU code is unique, you got to do it like this
#post = Post.new(params[:post])
#post.detail = Inventory.where(:sku_code => #post.sku_code).first.try(:detail)
first will fetch the first (and possibly only) record from the database. try will try to fetch detail if the returned Inventory was not nil.
Check this blog post to learn more about try method.

Related

Controller syntax Ruby on Rails 6

Having an issue with displaying only three posts on a page. Here is the closest I've gotten to getting the controller working with a param.
def index
#Post = Post.all
#Posts = Post.find.limit('3').order('date_posted')
end
This is rendering a syntax error of sorts because it wants an ID, but I don't want to give it an ID, I want it to find the three most recent posts. How should I go about that?
Try this way
def index
#recent_posts = Post.limit(3).order(date_posted: :desc)
end
What's wrong in your code
all gives you all the objects for a model
find and find_by give you just one object which meet the id passed to find or the first one which meets the conditions passed to find_by

Got ForbiddenAttributesError when inserting an object with association

I ask you a little help as I'm starting with Ruby on Rails with a problem that is still bothering me after searching docs and forums.
The problem raises when trying to insert an object of a class that has an association of type "belongs to" with another class.
In this situation, after submitting in the "new" form, Rails gives me a ForbiddenAttributesError in this line of Enterprise controller :
#enterprise = #country.enterprises.build(params[:enterprise])
I don't know how it gives me that error since I'm sending all parameters from the view , and specified all parameters as white-listed in Enterprise class:
controller/enterprises_controller.rb
def new
#country = Country.find(params[:country_id])
#enterprise = #country.enterprises.build
end
def create
#country = Country.find(params[:country_id])
#enterprise = #country.enterprises.build(params[:enterprise])
if #enterprise.save
redirect_to country_enterprise_url(#country,#enterprise)
else
render :action => 'new'
end
end
private
def enterprise_params
params.require(:enterprise).permit(:param1,:param2,:param3)
end
Thanks in advance.
You are creating a 'permission' private action for permitting params, but not using it when creating instance..
instead of :
#enterprise = #country.enterprises.build(params[:enterprise])
write :
#enterprise = #country.enterprises.build(enterprise_params)
meaning: the name of the action
EDIT: Hence - it's not going through the params.require.permit validation
Please change the line to:
#enterprise = #country.enterprises.build(enterprise_params)

Undefined method in professors controller

I have a system that lets users or guests write a review. If users write a review it is associated with their user_id. If guests write a review they are asked to provide a username which is stored in a column called "guest" in the reviews database.
I'm not entirely sure how to do this but what I've done with the professor_controller is:
def show
#review = Review.where(professor_id: #professor.id).order("created_at DESC")
#avg_review = #review.average(:hw)
if #review.user_id = !nil
#user = User.where(id: #review.user_id)
else
#user = #review.guest
end
render
end
However, this yields an error:
NoMethodError in ProfessorsController#show
undefined method `user_id=' for #<Review::ActiveRecord_Relation:0x007fed19228e28>
I was getting this error even before I put the if statement in. I had the same problem when my controller looked like:
def show
#review = Review.where(professor_id: #professor.id).order("created_at DESC")
#avg_review = #review.average(:hw)
#user = User.where(id: #review.user_id)
end
#review works fine so does #avg_review. The Reviews table has a user_id column and the Users table has an id column.
You are getting an ActiveRecord::Relation (a collection of Reviews), not a single instance of Review. You will need to do Review.where(professor_id: #professor.id).order("created_at DESC").first or Review.find_by_user_id(#professor.id) to return a single instance.
That said, it sounds like this relationship isn't modeled properly, or there's a better way to express what you want to do through other means. Can you route take in the id of a review as a param?
Your #review variable actually holds an ActiveRecord::Relation object, like it clearly says in the error message:
NoMethodError in ProfessorsController#show
undefined method `user_id=' for #<Review::ActiveRecord_Relation:0x007fed19228e28>
That's because where always returns a Relation, even if it finds only one
record.

Find if value is present in a list

I have a post controller that allows you to select a profession. I also have a work controller that has a list of professions stored seperated by commas. Eg:
Post has a row called profession, and only allows you to choose 1.
Work has a row called profession that are stored like this: business, law, accounting.
What I would like to do is once you save your post, take you to a page that shows work where Post profession is equal to Work profession. (Only relevant work show)
How would I go about doing this?
This sounds like what you're trying to do.
posts_controller.rb
def create
#post = Post.create(post_params)
if #post.save
redirect_to some_other_path(post_id: #post.id)
else
# handle error
end
end
some_controller.rb
def some_action
#post = Post.find(params[:post_id])
#works = Work.where("profession like ?", "%#{#post.profession}%")
end
Since you're using Postgres, you can use like which will match patterns within a field. This is more of a search functionality than a way of associating records. So if you have a Post that has a profession of "market", the like would match "market" and "marketing".
It might prove to be cleaner and easier to have Profession be a separate model. Post could belong_to, and Work could have_many.

Constructing a Rails ActiveRecord where clause

What's the best way to construct a where clause using Rails ActiveRecord? For instance, let's say I have a controller action that returns a list of blog posts:
def index
#posts = Post.all
end
Now, let's say I want to be able to pass in a url parameter so that this controller action only returns posts by a specific author:
def index
author_id = params[:author_id]
if author_id.nil?
#posts = Post.all
else
#posts = Post.where("author = ?", author_id)
end
end
This doesn't feel very DRY to me. If I were to add ordering or pagination or worse yet, more optional URL query string params to filter by, this controller action would get very complicated.
How about:
def index
author_id = params[:author_id]
#posts = Post.scoped
#post = #post.where(:author_id => author_id) if author_id.present?
#post = #post.where(:some_other_condition => some_other_value) if some_other_value.present?
end
Post.scoped is essentially a lazy loaded equivalent to Post.all (since Post.all returns an array
immediately, while Post.scoped just returns a relation object). This query won't be executed until
you actually try to iterate over it in the view (by calling .each).
Mmmh, the best approach you want to use can be to spread this in 2 actions
def index
#post = Post.all
end
def get
#post = Post.where("author=?", params[:author_id])
end
IMHO it has more sense if you think about a RESTful API, index means to list all and get (or show) to fetch the requested one and show it!
This question is pretty old but it still comes up high in google in 2019, and also some earlier answers have been deprecated, so I thought I would share a possible solution.
In the model introduce some scopes with a test for the existence of the parameter passed:
class Post
scope :where_author_ids, ->(ids){ where(author_id: ids.split(‘,’)) if ids }
scope :where_topic_ids, ->(ids){ where(topic_id: ids.split(‘,’)) if ids }
Then in the controller you can just put as many filters in as you wish e.g:
def list
#posts = Post.where_author_ids(params[:author_ids])
.where_topic_ids(params[:topic_ids])
.where_other_condition_ids(params[:other_condition_ids])
.order(:created_at)
The parameter can then be a single value or a comma separated list of values, both work fine.
If a param doesn’t exist it simply skips that where clause and doesn’t filter for that particular criteria. If the param exists but its value is an empty string then it will ‘filter out’ everything.
This solution won’t suit every circumstance of course. If you have a view page with several filters on, but upon first opening you want to show all your data instead of no data until you press a ‘submit’ button or similar (as this controller would) then you will have to tweak it slightly.
I’ve had a go at SQL injecting this and rails seems to do a good job of keeping everything secure as far as I can see.
You should model url using nested resources. The expected url would be /authors/1/posts. Think of authors as resources. Read about nested resources in this guide: http://guides.rubyonrails.org/routing.html (scroll to 2.7 - Nested Resources).
Would something like this work?
def get
raise "Bad parameters...why are you doing this?" unless params[:filter].is_a?(Hash)
#post = Post.where(params[:filter])
end
Then you can do something like:
?filter[author_id]=1&filter[post_date]=... etc.

Resources